7.7 Spring AOP底层实现,以及两种动态代理的实现(建议自己手动实现两种代理方式); 您所在的位置:网站首页 动态代理底层是反射吗 7.7 Spring AOP底层实现,以及两种动态代理的实现(建议自己手动实现两种代理方式);

7.7 Spring AOP底层实现,以及两种动态代理的实现(建议自己手动实现两种代理方式);

2024-07-07 01:49| 来源: 网络整理| 查看: 265

转载:https://www.cnblogs.com/hublogs/p/12035415.html

AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(例如性能监视、事务管理、安全检查、缓存、日志记录等)

切面:需要代理一些方法和增强代码

AOP的应用场景

场景一:记录日志

场景二:监控方法运行时间 (监控性能)

场景三: 权限控制

场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )

场景五: 事务管理 (调用方法前开启事务, 调用方法后提交或者回滚、关闭事务 )

AOP编程底层实现机制

AOP 就是要对目标进行代理对象的创建, Spring AOP是基于动态代理的,分别基于两种动态代理机制: JDK动态代理和CGLIB动态代理

方式一:JDK动态代理

JDK动态代理,针对目标对象的接口进行代理 ,动态生成接口的实现类 (必须有接口)

过程要点

1.必须对接口生成代理

2.采用Proxy对象,通过newProxyInstance方法为目标创建代理对象。

该方法接收三个参数 :

(1)目标对象类加载器

(2)目标对象实现的接口

(3)代理后的处理程序InvocationHandler

3.实现InvocationHandler 接口中 invoke方法,在目标对象每个方法调用时,都会执行invoke

service层

//接口(表示代理的目标接口) public interface ICustomerService { //保存 void save(); //查询 int find(); } //实现层 public class CustomerServiceImpl implements ICustomerService{ @Override public void save() { System.out.println("客户保存了。。。。。"); } @Override public int find() { System.out.println("客户查询数量了。。。。。"); return 100; } }

JDK动态代理工厂

//专门用来生成jdk的动态代理对象的-通用 public class JdkProxyFactory{ //target目标对象 private Object target; //注入target目标对象 public JdkProxyFactory(Object target) { this.target = target; } public Object getProxyObject(){ /** * 参数1:目标对象的类加载器 * 参数2:目标对象实现的接口 * 参数3:回调方法对象 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { //如果是保存的方法,执行记录日志操作 if(method.getName().equals("save")){ System.out.println("增强代码:写日志了。。。"); } //目标对象原来的方法执行 Object object = method.invoke(target, args);//调用目标对象的某个方法,并且返回目标对象 return object; } }); } }

测试方法

//目标:使用动态代理,对原来的方法进行功能增强,而无需更改原来的代码。 //JDK动态代理:基于接口的(对象的类型,必须实现接口!) @Test public void testJdkProxy(){ //target(目标对象) ICustomerService target = new CustomerServiceImpl(); //实例化注入目标对象 JdkProxyFactory jdkProxyFactory = new JdkProxyFactory(target); //获取 Object代理对象:基于目标对象类型的接口的类型的子类型的对象 //必需使用接口对象去强转 ICustomerService proxy = (ICustomerService)jdkProxyFactory.getProxyObject(); //调用目标对象的方法 proxy.save(); System.out.println("————————————————————"); proxy.find(); } 注意

JDK动态代理产生的对象不再是原对象

错误: CustomerServiceImpl proxy = (CustomerServiceImpl)jdkProxyFactory.getProxyObject(); 正确 ICustomerService proxy = (ICustomerService)jdkProxyFactory.getProxyObject(); 方式二:Cglib动态代理

Cglib的引入为了解决类的直接代理问题(生成代理子类),不需要接口也可以代理

该代理方式需要相应的jar包,但不需要导入。因为Spring core包已经包含cglib ,而且同时包含了cglib 依赖的asm的包(动态字节码的操作类库)

//没有接口的类 public class ProductService { public void save() { System.out.println("商品保存了。。。。。"); } public int find() { System.out.println("商品查询数量了。。。。。"); return 99; } }

使用cglib代理

//cglib动态代理工厂:用来生成cglib代理对象 public class CglibProxyFactory implements MethodInterceptor{ private Object target; //注入代理对象 public CglibProxyFactory(Object target) { this.target = target; } //获取代理对象 public Object getProxyObject(){ //1.代理对象生成器(工厂思想) Enhancer enhancer = new Enhancer(); // 类加载器 enhancer.setClassLoader(target.getClass().getClassLoader()); //2.在增强器上设置两个属性 //设置要生成代理对象的目标对象:生成的目标对象类型的子类型 enhancer.setSuperclass(target.getClass()); //设置回调方法 enhancer.setCallback(this); //3.创建获取对象 return enhancer.create(); } //回调方法(代理对象的方法) /** * 参数1:代理对象 * 参数2:目标对象的方法对象 * 参数3:目标对象的方法的参数的值 * 参数4:代理对象的方法对象 */ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //如果是保存的方法,执行记录日志操作 if(method.getName().equals("save")){ System.out.println("增强代码:写日志了。。。"); } //目标对象原来的方法执行 //调用目标对象的某个方法,并且返回目标对象 Object object = method.invoke(target, args); return object; } }

测试方法

//cglib动态代理:可以基于类(无需实现接口)生成代理对象 @Test public void testCglibProxy(){ //target目标: ProductService target = new ProductService(); //代理工厂对象,注入目标 CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(target); //获取proxy //代理对象,其实是目标对象类型的子类型 ProductService proxy = (ProductService)cglibProxyFactory.getProxyObject(); //调用代理对象的方法 proxy.save(); System.out.println("—————————————————————"); proxy.find(); } 总结

spring在运行期,生成动态代理对象,不需要特殊的编译器

Spring AOP 优先对接口进行代理 (使用Jdk动态代理)如果目标对象没有实现任何接口,才会对类进行代理 (使用cglib动态代理)

需要注意的

1.对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统,所以spring默认是使用JDK代理。对类代理是让遗留系统或无法实现接口的第三方类库同样可以得到通知,这种方式应该是备用方案

2.标记为final的方法不能够被通知。spring是为目标类产生子类。任何需要被通知的方法都被复写,将通知织入。final方法是不允许重写的

3.spring只支持方法连接点:不提供属性接入点,spring的观点是属性拦截破坏了封装。面向对象的概念是对象自己处理工作,其他对象只能通过方法调用的得到的结果



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有