SpringAOP中的动态代理技术深入解析
动态代理
Spring的aop实现主要应用了JDK动态代理和Cglib动态代理 这2种代理。
org.springframework.aop.framework.JdkDynamicAopProxy org.springframework.aop.framework.CglibAopProxy
spring默认使用JDK动态代理实现AOP,类如果实现了接口,spring就会用JDK动态代理实现AOP. 如果目标类没有实现接口,spring则使用Cglib动态代理来实现AOP.
- jdk动态代理的优势:jdk自身支持,减少依赖,可随jdk平滑升级,代码实现简单
- cglib动态代理的优势:无需实现接口,达到无侵入,只操作我们关系的类,而不必为其他相关类增加工作量
spring事务便是基于spring aop实现的, spring事务的一些失效场景,如
1.使用了private方法,导致事务失效(被动态代理的方法必须是public)
2.使用了final方法,导致事务失效(如果方法定义为final,JDK动态代理和cglib动态代理无法重写该方法)
3.同一类内部方法调用:直接使用this对象调用方法,无法生成代理方法,导致事务失效
测试使用Cglib动态代理
定义被代理的方法
package cn.demo.cglib; public class OrderService { /** * 被动态代理的方法应该是public公共的 * @param orderNo */ public void order(String orderNo){ System.out.println("order something..."); } }
定义cglib动态代理时触发的拦截器
package cn.demo.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * 动态代理类,实现方法拦截器MethodInterceptor接口 */ public class LogInterceptor implements MethodInterceptor { //cglib动态代理,基于ASM机制实现,通过生成目标类的子类作为代理类 //使用cglib中的Enhancer来生成代理对象子类, public Object getProxyInstance(Class targetClass){ //1.工具类 Enhancer enhancer = new Enhancer(); //2.设置父类 enhancer.setSuperclass(targetClass); //3.设置回调函数 enhancer.setCallback(this); //4.创建子类(代理对象) return enhancer.create(); } //并实现MethodInterceptor的intercept方法来实现增强功能 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("LogInterceptor: Before invoke---"); Object obj = methodProxy.invokeSuper(o,objects); System.out.println("LogInterceptor: After invoke---"); return obj; } }
使用cglib动态代理出的实例
package cn.demo.cglib; public class CglibTest { public static void main(String[] args) { //Cglib动态代理特点 //1.需要引入cglib依赖jar (一般spring的核心包已经有了cglib依赖) //2.被代理的类不需要接口信息,Cglib动态代理可以拦截并包装被代理类的所有方法 //3.代理类要实现MethodInterceptor接口 //4.代理类使用cglib中的Enhancer来生成目标对象子类 //5.目标类不能为final,因为final类不能创建子类 OrderService orderService = (OrderService) new LogInterceptor() .getProxyInstance(OrderService.class); orderService.order("123"); } }
测试使用jdk动态代理
定义被代理的方法及其接口
package cn.demo.proxy; public interface UserService { void login(String username, String password); }
package cn.demo.proxy; //jdk动态代理的致命缺点就是目标类必须实现某个接口 public class UserServiceImpl implements UserService{ @Override public void login(String username, String password) { System.out.println("User Login Service!"); } }
定义jdk动态代理时触发的拦截器
package cn.demo.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //通过实现InvocationHandler接口完成代理逻辑 public class LogHandler implements InvocationHandler { /** * 被代理的对象,实际的方法执行者 */ Object target; public LogHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在函数invoke之前之后,可以进行一些自定义操作 //如 日志、事务、拦截器、权限控制等 System.out.println("Before Login ---"); Object result = method.invoke(target,args); System.out.println("After Login ---"); return result; } }
使用jdk动态代理出的实例
package cn.demo.proxy; import java.lang.reflect.Proxy; public class JdkProxyTest { public static void main(String[] args) { //创建被代理的对象, UserService接口的实现类 UserServiceImpl userService = new UserServiceImpl(); //创建代理对象,包含3个参数 ClassLoader 、 目标类实现接口数组、 事件处理器 UserService userProxy = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new LogHandler(userService) ); //用代理出的实例调用login方法 userProxy.login("admin", "123456"); }
到此这篇关于SpringAOP中的动态代理技术深入解析的文章就介绍到这了,更多相关SpringAOP动态代理技术内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot ThreadLocal 简单介绍及使用详解
ThreadLocal 叫做线程变量,意思是 ThreadLocal 中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量,这篇文章主要介绍了SpringBoot ThreadLocal 的详解,需要的朋友可以参考下2024-01-01kafka并发写大消息异常TimeoutException排查记录
这篇文章主要为大家介绍了kafka并发写大消息异常TimeoutException的排查记录及解决方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步2022-02-02POI XSSFSheet shiftRows bug问题解决
这篇文章主要介绍了POI XSSFSheet shiftRows bug问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-07-07Spring Boot自定义 Starter并推送到远端公服的详细代码
这篇文章主要介绍了Spring Boot自定义 Starter并推送到远端公服,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-09-09
最新评论