spring学习笔记(四)——AOP
慕课网,spring入门,5-1 AOP基本概念及特点
https://www.imooc.com/video/4032
AOP概念
AOP:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
主要功能:日志记录,性能统计,安全控制,事物管理,异常处理等。
所有基于配置文件的aspect,只支持单例模式。
实现方式
- 预编译,AspectJ
- 运行期动态代理(jdk动态代理,CGLib动态代理),SpringAOP,JBossAOP
几个概念
官方文档中的概念
advice的类型
官方文档说明
有接口和无接口的spring aop的实现区别
- spring aop默认使用标准的java se动态代理作为aop代理,使得任何接口都可以被代理。
- spring aop也可以使用CGLIB代理。
基于配置的aop的实现
spring所有的切面和通知器都必须放在一个<aop:config>内(每个配置可以包含多个<aop:config>元素),每个<aop:config>可以包含pointcut、advisor、aspect元素(必须按照这个顺序声明)
pointcut
切点类型说明
只有spring aop支持的
@开头表示按注解匹配的
配置aop
- 前置通知的两种配置方式
- 返回通知的两种配置方式
- 抛出异常通知
- 后置通知,不论方法正常执行返回还是抛出异常,都知执行这个通知,
- 环绕通知
- 为通知传递参数
Introductions
- 简介允许一个切面声明一个实现指定接口的通知对象,并提供了一个接口实现类代表这些对象。
- 由<aop:aspect>中的<aop:declare-parents>元素声明。该元素用于声明所有匹配的类型拥有一个新的parent。
advisor
- advisor就像一个小的自包含的切面,只有一个advice。
- 切面自身通过一个bean表示,并且必须实现某个advice接口,同时,advisor也可以很好地利用AspectJ的切入点表达式。
- spring中通过配置文件中<aop:advisor>元素支持advisor。实际使用中,多数情况下它会和transactional advice配合使用。
- 为了定义一个advisor的优先级,以便让advice有序,可以使用order属性来定义advisor的顺序。
Spring AOP API
- NameMatchMethodPointcut接口
- BeforeAdvice接口
- ThrowsAdvice接口
afterThrowing方法中,Exception参数是必有的,其他参数可以没有。
AfterReturningAdvice接口
- around advice,MethodInterceptor接口
- introduction advice,IntroductionInterceptor
- advisor
ProxyFactoryBean
- 创建Spring AOP代理的基本方法是使用org.springframework.aop.framework.ProxyFactoryBean
- 这可以完全控制切入点和通知以及它们的顺序
- 使用ProxyFactoryBean或其他IoC相关类来创建AOP代理的最重要好处是通知和切入点也可以由IoC来管理
- 被代理类没有实现任何接口,使用CGLIB代理;否则使用jdk代理
- 通过设置proxyTargetClass为true,可以强制使用CGLIB
- 如果目标类实现了一个或多个接口,那么创建代理的类型将依赖ProxyFactoryBean的配置
- 如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或多个全限定接口名,那么基于jdk的代理将被创建
- 如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个或多个接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口,创建一个基于jdk的代理
比如下文配置中,personUser bean最终引用到的是personTarget bean。
- 可以使用匿名内部bean来隐藏目标和代理之间的区别
- 前面的例子中如果没有Person接口,spring会使用CGLIB代理,而不是jdk动态代理
- 如果想,可以强制再任何情况下使用CGLIB,即使有接口
- CBLIB代理的工作原理是运行时生成目标类的子类,spring配置这个生成的子类委托方法调用原来的目标
- 子类是用来实现Decorator模式,织入通知
- CGLIB的代理对用户是透明的,需要注意
- final方法不能被通知,因为它们不能被覆盖
- 不用把CGLIB添加到classpath中,在spring3.2中,CGLIB被重新包装并包含在spring核心jar(即基于CGLIB的aop就像jdk动态代理一样“开箱即用”)
- 用*做通配符,匹配所有拦截器加入通知链
- 使用父子bean定义,以及内部bean定义,可能会带来更清洁和更简洁的代理定义(抽象属性标记父bean定义为抽象的,它不能被实例化)