演示了错误案例:同X类的两个方法 a( ) , b( ) :
方法 a( ) 用 @Cacheable 来注释,而 b( ) 方法调用了 a( ) 方法,而 b() 方法本身没有用 @Cacheable 注释。在调用端调用 b 方法,发现没有生效缓存。
问题原因:b() 方法调用的是 this.a() 方法,而不是被代理后的 a() 方法,我们的目的是要调用被代理后的 a() 方法!
解决方法(1):ApplicationContextHolder.getContext().getBean(xx.class);
得到的返回 就是X类型被代理后的代理类型 Xproxy。
然后改写 b() 方法,要使用 Xproxy.a() 即可以访问 X类被代理后的类型的对应方法。
解决方法(2):不要在这个X类内部调用 a() ,而是要在另1个方法Y类内部里实现 b() ,这样就会直接走 proxy 而不是走 this 方法
(业务代码举例:用户操作记录的日志保存)
@Transactional 的意义,在 jpa 里默认对每个操作都有事务控制,但是在一个方法体中存在多个操作时(即,包含多个子事务时)则没有大的事务进行包裹,不会进行统一回滚。
责任链模式, Handler 对象的抽象方法 handleProcess(),由多个实现类去实现,这些多个实现类又组合成了 Handler 。
Handler 对象里自带一个属性叫 successor 它的类型同样是 Handler 。执行时先执行自身的 handleProcess () 方法,再执行 Handler 内的的 successor 的execute() 方法,实现了链式调用逐级调用 ,直到最后的 successor 为 null 为止。
这节课通过源代码分析,Proxy.invoke 方法的运行机制。如何通过接口,handler一步步生产代理对象。
注意这里,既然他说基于接口来实现的:
在Proxy.newProxyInstance() 第 2个参数里一定要传入 "接口.class" ,而不是 "类.class"
那么光看接口怎么知道代理的目标具体是那个类呢? 就是第3个 参数里即 handler 里面决定的。
调用方通过代理对象间接对目标进行调用,代理对象就可以在执行目标对象的方法前后进行些额外的操作。
调用接口里定义的方法,代理对象和目标对象共同作为接口实现类,代理对象在方法里调用目标对象的同名方法,并在执行前后做自定义的额外操作。
织入AOP的时机: 编译器,类加载器,运行期
运行期织入:动态代理来实现
这里介绍了 @Pointcut("this..") 和 @Pointcut("target()") 的区别: 在于拦截的方法是原对象还是代理对象
@Pointcut("within() ..) 表达式匹配整个类的所用方法,或者整包下的所用类的所有方法。
主要注解
@Aspect表示这个类是个切面类
@Pointcut 定义在哪些类和方法里植入aop代码
Advice 表示植入的时间(before,after,around)
编程范式: 面向对象,面向过程,函数式,事件驱动,面向切面(面向切面是对面向对象的补充)
应用场景:权限控制,缓存控制,事务控制,日志监控,异常处理
AOP
编程范式概览:
面向过程编程
面向对象编程
函数式编程
事件驱动编程
面向切面编程
AOP的初衷:
DRY:代码重复问题
SoC: 水平分离: 展示层->服务层->持久层
垂直分离: 模块划分(订单、库存等)
切面分离: 分离功能性需求与非功能性需求
使用AOP的好处
非功能性需求
@cacheable缓存
SpringSecuerity的PreAothorize验证
@transaction在@Service的方法进行事务控制
@excution 切面条件,Advice执行时机,精讲
@annotation 拦截条件,AOP
888888888888888888888888
7777777777777777
6666666666666666666
555555555555555555555
444444444444444444444