代理模式
所谓代理模式,就是为其它对象提供一个代理来控制对目标对象的访问,代理类不实现具体的服务,利用委托类来完成服务。
静态代理
静态代理十分简单。创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public interface Hello { public void say(String s) throws IllegalArgumentException; }
public class HelloImpl implements Hello { @Override public void say(String s) throws IllegalArgumentException{ if(s == null || s.length() == 0) throw new IllegalArgumentException("参数不合法"); System.out.println(s); } }
public class HelloStaticProxy implements Hello { Hello hello;
public HelloStaticProxy(Hello hello){ this.hello = hello; } @Override public void say(String s) throws IllegalArgumentException { System.out.println("before method invoke"); String re = null; boolean isException = false; try{ this.hello.say(s); }catch (IllegalArgumentException e){ isException = true; } System.out.println("after method invoke"); if(isException) System.out.println("after method throw Exception"); } public static void main(String[] args){ Hello hello = new HelloImpl(); Hello proxy = new HelloStaticProxy(hello); proxy.say(null); System.out.println("------------------"); proxy.say("hello"); } }
|
以上代码运行结果如下:
1 2 3 4 5 6 7
| before method invoke after method invoke after method throw Exception ------------------ before method invoke hello after method invoke
|
这样,当需要代理一个类的时候,只要编写一个该类的静态代理对象即可,但是,如果需要代理的对象很多,就需要编写大量的代理类,十分麻烦 。
动态代理
动态代理能够利用反射机制在程序运行期间生成代理类。在 java.lang.reflect 包下的 Proxy 类有一个静态方法 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),通过该方法可以获得动态代理类。它需要一个类加载器,类的接口数组,以及一个实现 InvocationHandler 接口的类。
InvocationHandler 中只声明了一个方法:Object invoke(Object proxy, Method method, Object[] args) throws Throwable ,通过这个方法,可以调用被代理类的方法,需要注意,invoke 参数中的 proxy 表示的是代理对象,而不是被代理对象,因此 method.invoke() 传入的参数不能是它,否则会循环调用。
上面的接口与接口实现类不变,创建一个实现了 InvocationHandler 的类完成动态代理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class MyProxyHandler implements InvocationHandler { Object target; public MyProxyHandler(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method invoke"); Object re = null; boolean isException = false; try{ re = method.invoke(target, args); }catch (Exception e){ isException = true; } System.out.println("after method invoke"); if(isException) { System.out.println("after method throw Exception"); return null; } return re; }
public static void main(String[] args){ Hello hello = new HelloImpl(); Hello helloProxy = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), new MyProxyHandler(hello)); helloProxy.say(null); System.out.println("-----------------"); helloProxy.say("hello"); } }
|
结果如下:
1 2 3 4 5 6 7
| before method invoke after method invoke after method throw Exception ----------------- before method invoke hello after method invoke
|
jdk动态代理必须要依靠接口实现,因为生成的代理类是 Proxy 的子类,而 Java 不允许多继承,所以需要接口来连接代理类与被代理类。