Java动态代理(JDK动态代理和cglib)
2021/11/25 1:10:35
本文主要是介绍Java动态代理(JDK动态代理和cglib),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
JDK动态代理
JDK的动态代理只允许代理接口
重要的类和接口Proxy和InvocationHandler
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)方法创建目标对象的代理对象
获取到目标对象的代理对象之后,执行目标对象的方法实际上是通过调用代理对象的invoke方法实现的
我们可以在invoke方法中增加额外的通用的逻辑来对目标对象进行增强
/** * @Description 代理对象 */ public class ProxyHandler implements InvocationHandler{ private Object target; public Object getProxyHandler(Object target){ this.target = target; Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object invoke = method.invoke(target, args); System.out.println("After"); return invoke; } }
获取到代理对象之后,像调用目标对象一样调用代理对象的方法,直观上和普通的调用没有任何区别,但是实际上调用的是代理对象的invoke方法,在invoke方法里面可以做的事情有很多,可以增强甚至重写某些方法,通过method.getName()来对指定方法进行处理
public class ProxyHandlerTest extends TestInit { @Autowired ISalesOrderFlowDomainService salesOrderFlowDomainService; @Test public void test(){ ProxyHandler proxyHandler = new ProxyHandler(); ISalesOrderFlowDomainService iSalesOrderFlowDomainService = (ISalesOrderFlowDomainService) proxyHandler.getProxyHandler(salesOrderFlowDomainService); SalesOrderFlowDTO salesOrderFlow = iSalesOrderFlowDomainService.getSalesOrderFlow("20210702000001", OrderFlowType.SIGNED); System.out.println(salesOrderFlow); } }
使用Cglib实现动态代理
Cglib不是jdk自带的jar包,需要下载并加入到项目中
CGLIB代理相关的类:
- net.sf.cglib.proxy.Enhancer 主要的增强类。
- net.sf.cglib.proxy.MethodInterceptor 主要的方法拦截类,它是Callback接口的子接口,需要用户实现。
- net.sf.cglib.proxy.MethodProxy JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用。
CGLIB动态代理的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数
实现MethodInterceptor接口
public class CglibProxy implements MethodInterceptor{ //主要的增强类。 private Enhancer enhancer = new Enhancer(); @Override /** * * @param o 是被代理对象 * @param method 调用方法的Method对象 * @param args 方法参数 * @param methodProxy * @return cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升 * @throws Throwable */ public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before " + methodProxy.getSuperName()); System.out.println(method.getName()); Object o1 = methodProxy.invokeSuper(o, args); //Object o2 = method.invoke(o, args); 使用这种方式会发生死循环,因为方法会被拦截 System.out.println("after " + methodProxy.getSuperName()); return o1; } public Object newProxyInstance(Class<?> c) { //设置产生的代理对象的父类。 enhancer.setSuperclass(c); //设置CallBack接口的实例 enhancer.setCallback(this); //使用默认无参数的构造函数创建目标对象 return enhancer.create(); } }
被代理对象和测试类
public class CglibDemo { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); Do o = (Do)cglibProxy.newProxyInstance(Do.class); System.out.println(o.doSomething(5)); } } class Do{ public int doSomething(int num){ System.out.println("方法执行中。。。。。。"); return num; } }
Jdk和Cglib 的区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
- 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
- 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
- 如果目标对象没有实现接口,必须采用CGLIB库.
spring会自动在JDK动态代理和CGLIB之间转换如何强制使用CGLIB实现AOP?
- 添加CGLIB库,SPRING_HOME/cglib/*.jar
- 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>
JDK动态代理和CGLIB字节码生成的区别? - JDK动态代理只能对实现了接口的类生成代理,而不能针对类
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
【参考文章】
【1】https://www.cnblogs.com/shijiaqi1066/p/3429691.html
这篇关于Java动态代理(JDK动态代理和cglib)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南