简单谈谈动态代理
什么是代理模式?
为其他对象提供一个代理以控制对某个对象的访问。
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
其实就是代理类 为被代理类 进行预处理消息 、过滤消息 并在此之后将消息转发 给被代理类 ,之后还能进行消息的后置处理
代理类和被代理类通常会存在关联关系(即上面提到的持有的被带离对象的引用),代理类本身不实现服务,而是通过调用被代理类中的方法来提供服务。
简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途,例如记录日志等
有哪些代理模式
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式——代理模式
而对于代理,根据创建代理类的时间点,又可以分为静态代理 和动态代理
静态代理 :由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口
、被代理类
、代理类
等确定下来。在程序运行之前,代理类的.class文件就已经生成。
动态代理 :代理类在程序运行时才被创建。代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的
各代理模式的实现
前置场景说明
我们以生活中的场景为例子
假设现在有一个Teacher教师接口,张老师类与王老师类
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 public interface Teacher { void speak () ; void rest () ; void standup (String studentName) ; } public class Wang implements Teacher { @Override public void speak () {System.out.println("王老师讲话。。。" );} @Override public void rest () {System.out.println("王老师休息。。。" );} @Override public void standup (String studentName) { System.out.println("王老师让" +studentName+"同学站起来" ); } } public class Zhang implements Teacher { @Override public void speak () {System.out.println("张老师讲话。。。" );} @Override public void rest () {System.out.println("张老师休息。。。" );} @Override public void standup (String studentName) { System.out.println("张老师让" +studentName+"同学站起来" ); } }
我们平时让其执行,都是使用接口的实现类,然后实例化执行
1 2 3 4 5 6 7 8 9 System.out.println("----------接口实现----------" ); Teacher zhang = new Zhang(); zhang.speak(); zhang.rest(); zhang.standup("小张" ); Wang wang = new Wang(); wang.speak(); wang.rest(); wang.standup("小王" );
这样非常方便就能执行方法
可是这也会产生一些问题
问题提出
如果我想让方法执行前后都记录成日志,应该怎么做?
俗话说得好,加一层能解决90%的问题,如果还是无法解决,那么就再加一层!
在每个方法具体代码前后都执行一次记录方法是不可取的
因为2个实现类共6条方法就需要写下12条重复代码
如果有10个类共有100个方法,那岂不是需要写下100条重复代码,这样明显是不易于维护的
静态代理
我们为zhang
和wang
都添加一个代理类
以ZhangProxy
为例
这样就可以解决掉前后记录日志的问题了,但是重复代码的问题依然存在:用泛型解决!
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 public class ZhangProxy implements Teacher { private Zhang zhang; public ZhangProxy (Zhang zhang) { this .zhang = zhang; } @Override public void speak () { System.out.println("before speak" ); zhang.speak(); System.out.println("after speak" ); } @Override public void rest () { System.out.println("before rest" ); zhang.rest(); System.out.println("after rest" ); } @Override public void standup (String studentName) { System.out.println("before standup" ); zhang.standup(studentName); System.out.println("after standup" ); } } System.out.println("----------静态代理----------" ); ZhangProxy zhangProxy = new ZhangProxy(new Zhang()); zhangProxy.speak(); zhangProxy.rest(); zhangProxy.standup("小静" ); WangProxy wangProxy = new WangProxy(new Wang()); wangProxy.speak(); wangProxy.rest(); wangProxy.standup("小王" );
泛型静态代理
这样就不需要重复编写多个代理类与前后记录日志的方法了
减少了大量的重复代码
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 45 46 47 48 49 50 51 52 53 54 55 56 57 public class AllProxy <T > implements Teacher { private T t; private Method[] methods; private Map<String,Method> temp; public AllProxy (T t) { this .t = t; this .methods = t.getClass().getMethods(); temp=new HashMap<>(); for (Method method : methods) { temp.put(method.getName(),method); } } @Override public void speak () { System.out.println("before speak" ); try { temp.get("speak" ).invoke(t); }catch (Exception e){ e.printStackTrace(); } System.out.println("after speak" ); } @Override public void rest () { System.out.println("before rest" ); try { temp.get("rest" ).invoke(t); }catch (Exception e){ e.printStackTrace(); } System.out.println("after rest" ); } @Override public void standup (String studentName) { System.out.println("before standup" ); try { temp.get("standup" ).invoke(t,studentName); }catch (Exception e){ e.printStackTrace(); } System.out.println("after standup" ); } } System.out.println("----------泛型静态代理----------" ); AllProxy<Wang> wangAllProxy = new AllProxy<>(new Wang()); wangAllProxy.speak(); wangAllProxy.rest(); wangAllProxy.standup("小王" ); AllProxy<Zhang> zhangAllProxy = new AllProxy<>(new Zhang()); zhangAllProxy.speak(); zhangAllProxy.rest(); zhangAllProxy.standup("小张" );
新的问题
这样虽然将重复编写代理类的问题解决了
可是实现了多个接口后,重写的方法会越来越多,不满足开闭原则 :程序对修改关闭,对扩展开放
那么就应该使用动态代理来解决这个问题
动态代理
具体步骤
通过实现 InvocationHandler
接口并重写invoke
方法创建自己的调用处理器
通过为 Proxy
类的newProxyInstance
方法,指定类加载器 ClassLoader
对象、一组被代理接口的 Class
数组与调用处理器的实例化对象来创建动态代理类实例
通过反射机制获得动态代理类的构造函数var5.getConstructor(constructorParams)
,其唯一参数类型是调用处理器接口类型constructorParams = new Class[]{InvocationHandler.class}
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入var6.newInstance(var2)
创建代理类
创建一个动态代理类DynamicProxy
,实现InvocationHandler
接口,重写invoke
方法
Object res = method.invoke(obj, objects);
通过反射执行method,其中obj被代理类的实例化对象 ,也就是上文中的Zhang或者Wang的实例化对象
被代理类执行的所有方法都被替换成执行了invoke方法,减少了99%的重复代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class DynamicProxy <T > implements InvocationHandler { private T obj; public DynamicProxy (T obj) { this .obj = obj; } @Override public Object invoke (Object o, Method method, Object[] objects) throws Throwable { System.out.println("before " +method.getName()); Object res = method.invoke(obj, objects); System.out.println("after " +method.getName()); return res; } }
Proxy.newProxyInstance
Proxy.newProxyInstance
方法有三个参数:
ClassLoader loader
: 用哪个类加载器去加载代理对象(等下用Factory工厂类去实例化代理,即工厂的class当做加载器)
Class<?>[] interfaces
: 动态代理类需要实现的接口(就是被代理的接口,Teacher这种)
InvocationHandler proxy
:InvocationHandler的实现类,也就是代理类
1 2 3 4 5 6 7 8 9 10 11 12 Zhang zhang = new Zhang(); DynamicProxy<Zhang> zhangDynamicProxy = new DynamicProxy<>(zhang); Teacher teacher = (Teacher)Proxy.newProxyInstance( Main.class.getClassLoader(), test.getClass().getInterfaces(), zhangDynamicProxy); teacher.standup("小代" );
before standup
张老师让小代同学站起来
after standup
动态代理工厂
上述执行实例化代理类有点麻烦了,如果我们用个代理工厂,以泛型的形式去实例化代理呢?
classLoader
用factory本身的:this.getClass().getClassLoader()
Class<?>[] interfaces
用泛型T的:t.getClass().getInterfaces()
InvocationHandler
还是用我们自定义的代理类模板:new DynamicProxy(t)
,别忘了将泛型对象传入
1 2 3 4 5 6 7 8 9 10 11 12 public class ProxyFactory { public <T> T getInstance (T t) { ClassLoader classLoader = this .getClass().getClassLoader(); Class<?>[] interfaces = t.getClass().getInterfaces(); DynamicProxy proxy = new DynamicProxy(t); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy); } }
那么我们实例化代理时,只需要一句话
1 Teacher mrZhang = new ProxyFactory().getInstance(new Zhang());
其实这个代理工厂类不仅仅可以实例化Teacher的代理,其他的类其实也可以代理
因为用了泛型,而无需指定具体类型
所以如果我们新建了一个Student
接口与接口的实现类Chen
一样可以代理执行,满足开闭原则 :无需修改任何代码,只需在调用时传入被代理的对象即可
1 2 3 4 5 6 7 8 9 10 11 12 Teacher mrZhang = new ProxyFactory().getInstance(new Zhang()); mrZhang.speak(); mrZhang.rest(); mrZhang.standup("小张" ); Teacher mrWang = new ProxyFactory().getInstance(new Wang()); mrWang.speak(); mrWang.rest(); mrWang.standup("小王" ); Student chen = new ProxyFactory().getInstance(new Chen()); chen.discuss();
before speak
张老师讲话。。。
after speak
————————
before discuss
小陈同学与同桌讨论题目
after discuss
本个人博客提供的内容仅用于个人学习,不保证内容的正确性。通过使用本站内容随之而来的风险与本站无关!