浅谈AOP的理解
AOP面向切面编程思想,在面向对象OOP的思想中,将模块纵向抽取成一个个对象,而面向切面编程思想,将相似功能的模块进行横向的抽取成一个切面。通常用于权限控制、事务管理、日志记录等公共操作的过程叫做面向切面编程思想,这种思想提高了代码的复用性降低了耦合性,提高了可扩展性可维护性。SpringAOP是基于动态代理来实现的,如果这个类实现了某个接口就使用jdk的动态代理去创建代理对象,如果没有实现某个接口就使用CGlib代理去创建一个被代理对象的子类作为代理。
扩展:在bean的创建过程中有一个步骤可以对bean进行扩展,AOP本身就是一个扩展功能,所以在beanPostProcesser后置处理方法来进行实现
应用场景
拦截器
实现一个自己的拦截器,需要实现HandlerInterceptor接口。接口内的三个核心方法如下:
1.preHandle():该方法在业务处理器处理请求之前调用。
2.postHandle():这个方法在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView 对象进行操作。
3.afterCompletion():在postHandle执行之后执行,发生异常也会执行。该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
拦截器在实现层面,并没有用到aop,并没有切面,通知这一类的代码,所以它的实现并不是基于aop的。但是拦截器从思想层面上,是面向切面编程的,是在controller这个层面上进行的代码织入。
@Transactional 是声明式事务管理 编程中使用的注解 基于AOP来实现的
访问权限:public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。
事务的不生效
-
接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效。
- 使用的final修饰的方法上使用@Transactional开启全局事务也会失效,因为cblib动态创建一个被代理对象的子类作为代理,而final修饰的类不能被继承或实现
- 使用private修饰的方法也会失效的,子类不能重载父类的private方法,使用无法使用代理导致失效
SpringCache基于AOP动态代理实现的
由于 SpringCache 是基于 Spring AOP 的动态代理实现,由于代理本身的问题,当同一个类中调用另一个方法,会导致另一个方法的缓存不能使用,这个在编码上需要注意,避免在同一个类中这样调用。
补充:通知(Advice)的类型:
前置通知 @Before(Before advice):
在某个连接点(Join point)之前执行的通知,但这个通知不能阻止连接点的执行(除非它抛出一个异常)。
返回后通知 @AfterRunning(After returning advice):
在某个连接点(Join point)正常完成后执行的通知。例如,一个方法没有抛出任何异常正常返回。
抛出异常后通知 @AfterThrowing(After throwing advice):
在方法抛出异常后执行的通知。
后置通知 @After(After(finally)advice):
当某个连接点(Join point)退出的时候执行的通知(不论是正常返回还是发生异常退出)。
环绕通知 @Around(Around advice):
包围一个连接点(Join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行.