1.AOP概念
在开发过程中会产生一些与主业务逻辑关系不大,但散落在代码各个部分难以维护的横切性问题,如日志记录、权限验证、事务管理、异常处理等。AOP就是处理这些横切性问题,AOP思想就是将这些问题与主业务分开,从而达到与主业务解耦的目的。
2.AOP术语
(1) Join point: 连接点,目标对象中的方法
(2) Advice: 通知,特定连接点上具体操作,具体有"around"、"before"和"after"三种通知
(3) Pointcut: 切点,多个连接点的集合,可用表达式表示目标连接点集合
(4) Target object: 目标对象,即需要增加的对象
(5) Aop proxy: 代理对象,Aop底层为jdk动态代理和cgLib代理,aop实质即为目标对象生成代理对象,从而对目标对象进行增强
(6) Weaving: 织入,将需要增强的通知增强进目标对象中
3. @AspectJ 支持
Spring对Aop的支持,底层自己实现了一套AOP逻辑,只是引入了AspectJ的注解支持,AOP是一种概念,SpringAop、AspectJ均为Aop的实现,Spring实现的Aop逻辑复杂,故引入了AspectJ的注解,底层仍为自己实现
3.1 Spring中引入切面实现
(1) 引入AspectJ依赖,目的为提供AspectJ注解支持
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
(2) 配置文件中增加@EnableAspectJAutoProxy
@Configuration
@ComponentScan("com.study.spring")
@EnableAspectJAutoProxy
public class SpringConfig {
}
(3) 书写切面对象,并将该对象交由Spring管理
@Aspect
@Component
public class UserAop {
}
(4)书写切入点
@Pointcut("execution(* com.study.spring.dao.*(..))")
public void pointCut(){
}
(5)书写通知即可完成切面实现
@Before("pointCut()")
public void beforeAdvice(){
System.out.println("before advice");
}
3.2 pointcut切面表达式
- execution
表示匹配连接点对应的包及其子包对象及对象中的方法,最小作用单元为方法级别
execution(* * com.study.spring.dao.*.*(..))
表示式解析:
第一个*:表示方法访问级别,可以为public
,private
,protect
,下述表达式表示只会给访问级别为public
的方法进行增aop
execution(public * com.study.spring.dao.*.*(..))
第二个*:表示方法返回类型,下述表达式表示只会给没有返回值的方法进行aop
execution(void com.study.spring.dao.*.*(..))
第三个表示式:表示方法路径,下述表示dao包及其所有子包,对应所有方法均为被增强
execution(* com.study.spring.dao..*(..))
execution表达式为我们常用表达式,表达式也比较多,在此就不做过多介绍,实际开发中可根据实际需求进行配置
- within
表示匹配连接点对应的包及其子包对象,最小作用单元为对象级别
(1)表示dao包下所有对象均会被增强
within(void com.study.spring.dao.*)
(2)下述表达式表示dao包及其子包中所有对象均会被增强
within(void com.study.spring.dao..*)
- target 及this
target:表示目标对象,即aop对应的原始对象
this:表示代理对象
/**
* 此处需要注意的是,如果配置设置proxyTargetClass=false,或默认为false,则是用JDK代理,否则使用的是CGLIB代理
* JDK代理的实现方式是基于接口实现,代理类继承Proxy,实现接口。
* 而CGLIB继承被代理的类来实现。
* 所以使用target会保证目标不变,关联对象不会受到这个设置的影响。
* 但是使用this对象时,会根据该选项的设置,判断是否能找到对象。
*/
@Pointcut("target(com.study.dao.IndexDaoImpl)")//目标对象,也就是被代理的对象。限制目标对象为com.study.dao.IndexDaoImpl类
@Pointcut("this(com.study.dao.IndexDaoImpl)")//当前对象,也就是代理对象,代理对象时通过代理目标对象的方式获取新的对象,与原值并非一个
@Pointcut("@target(com.study.anno.ExtAnno)")//具有@ExtAnno的目标对象中的任意方法
@Pointcut("@within(com.study.anno.ExtAnno)")//等同于@target
- @target、@arges、@within、@annotation
带有@,与上述表示方式类似,唯一区别在于这些表达式只针对于注解形式
切点配置的表达式较大,可根据实际开发中所遇具体配置,在此不做过多介绍
3.3 Advice通知
(1)前置通知(@before):表示在方法执行前进行增强
@Before("pointCut()")
public void beforeAdvice(){
System.out.println("before advice");
}
(2)后置通知(@After):表示在方法执行后进行增强
@After("pointCut()")
public void beforeAdvice(){
System.out.println("after advice");
}
(3)环绕通知(@Around):表示在方法执行前、执行后均增强
@Around("pointCut()")
public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("before around advice");
pjp.proceed();
System.out.println("after around advice");
}
pjp.proceed()
方法表示目标对象中要增加的方法,即为连接点方法
pjp
常用方法:
getArgs()
:返回方法参数
getThis()
:返回代理对象
getTarget()
:返回目标对像`