本文最后更新于:May 2, 2022 am
积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里,不积小流无以成江海。齐骥一跃,不能十步,驽马十驾,功不在舍。面对悬崖峭壁,一百年也看不出一条裂缝来,但用斧凿,能进一寸进一寸,能进一尺进一尺,不断积累,飞跃必来,突破随之。
目录 静态代理 静态代理就和平常自己写一些工具类差不多。
静态代理实现步骤:
定义一个接口及其实现类;
创建一个代理类同样实现这个接口
将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。(简单说就是把被代理对象进行一次封装)
实现 以一个邮件发送为例。
接口 package com.proxyStu.staticProxy;public interface EmailSendService { void sendMSG (String email,String msg) ; }
实现类 package com.proxyStu.staticProxy;public class EmailSendServiceImpl implements EmailSendService { @Override public void sendMSG (String email,String msg) { System.out.println("发送给 " +email+" 的消息为:" +msg); } }
代理类 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 package com.proxyStu.staticProxy;public class EmailSendProxy implements EmailSendService { private EmailSendService emailSendService; EmailSendProxy(EmailSendService ess){ this .emailSendService = ess; } @Override public void sendMSG (String email, String msg) { System.out.println("发送前的处理逻辑" ); emailSendService.sendMSG(email,msg); System.out.println("发送后的处理逻辑" ); } }
使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.proxyStu.staticProxy;public class ProxyTest { public static void main (String[] args) { EmailSendService emss = new EmailSendServiceImpl(); EmailSendProxy emailSendProxy = new EmailSendProxy(emss); emailSendProxy.sendMSG("123465@qq.com" , "Hello World!" ); } } 发送前的处理逻辑 发送给 123465 @qq .com 的消息为:Hello World! 发送后的处理逻辑
动态代理 动态代理的实现方式有很多种,比如 JDK 动态代理 、CGLIB 动态代理 等等。
JDK动态代理 只能代理实现了接口的类或者直接代理接口。
介绍 Java 动态代理机制中 InvocationHandler
接口和 Proxy
类是核心。
我们会使用 newProxyInstance()
来生成一个代理对象。源码中为:
public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
而这个方法一共有 3 个参数:
loader :类加载器,用于加载代理对象。即加载我们自己写的类。
interfaces : 被代理类实现的一些接口;即类中的方法。
h : 实现了 InvocationHandler
接口的对象;自定义重写的一个类,该类实现了InvocationHandler
接口,用于自定义一些处理逻辑。
要实现动态代理,还需要实现InvocationHandler
来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler
接口类的 invoke
方法来调用。源码
public interface InvocationHandler { public Object invoke (Object proxy, Method method, Object[] args) throws Throwable ; }
三个参数:
通过Proxy
类的 newProxyInstance()
创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler
接口的类的 invoke()
方法。 所以可以在 invoke()
方法中自定义处理逻辑,比如在方法执行前后做什么事情。
步骤
定义一个接口及其实现类;
自定义 InvocationHandler
并重写invoke
方法,在 invoke
方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象;这里我们可以封装成一个工厂类。
实现 还是以发送一个邮件为例。
接口 package com.proxyStu.jdkProxy;public interface EmailSendService { void sendMSG (String email,String msg) ; }
实现类 package com.proxyStu.jdkProxy;public class EmailSendServiceImpl implements EmailSendService { @Override public void sendMSG (String email,String msg) { System.out.println("发送给 " +email+" 的消息为:" +msg); } }
代理类 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 package com.proxyStu.jdkProxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class myInvocationHandler implements InvocationHandler { private Object target; myInvocationHandler(Object obj){ this .target = obj; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行前的其他逻辑" ); Object res = method.invoke(target,args); System.out.println("执行后的其他逻辑" ); return res; } }
其实,这里就已经完成了代理。可以直接使用了。如下:
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 package com.proxyStu;import com.proxyStu.staticProxy.EmailSendService;import com.proxyStu.staticProxy.EmailSendServiceImpl;import java.lang.reflect.Proxy;public class proxyTest { public static void main (String[] args) { EmailSendService obj = new EmailSendServiceImpl(); EmailSendService o = (EmailSendService)Proxy.newProxyInstance( obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new myInvocationHandler(obj) ); o.sendMSG("123456@qq.com" ,"Hello World2!" ); } } 执行前的其他逻辑 发送给 123456 @qq .com 的消息为:Hello World2! 执行后的其他逻辑
可以看见,在创建代理对象的时候是比较复杂的;如果需要创建多次时,那么就会出现代码的冗余,也不方便。所以,我们可以将其进行封装。
封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.proxyStu.jdkProxy;import java.lang.reflect.Proxy;public class myProxyFactory { public static Object getProxy (Object obj) { return Proxy.newProxyInstance( obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new myInvocationHandler(obj) ); } }
使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.proxyStu;import com.proxyStu.staticProxy.EmailSendService;import com.proxyStu.staticProxy.EmailSendServiceImpl;public class proxyTest { public static void main (String[] args) { EmailSendService o = (EmailSendService)myProxyFactory.getProxy(new EmailSendServiceImpl()); o.sendMSG("123465@qq.com" ,"Hello World3 !" ); } } 执行前的其他逻辑 发送给 123465 @qq .com 的消息为:Hello World3 ! 执行后的其他逻辑
这样进行封装,极大的方便了使用和减少了代码量。
CGLIB 动态代理 CGLIB 可以代理未实现任何接口的类。 在 CGLIB 动态代理机制中 MethodInterceptor
接口和 Enhancer
类是核心。
总结