AOP
概念
AOP:Aspect Oriented Programming:面向切面编程,AOP底层走的就是代理模式
使用场景:事务管理、日志管理、权限控制等,这些服务与业务无关,但是又与业务模块有直接的关系,这些被称为交差业务模块,这些交叉业务模块就需要使用AOP来实现
maven:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
术语
- 目标对象(target):需要被增强的对象
- 连接点(JoinPoint):目标对象中定义的所有方法
- 通知(Advice):增强的功能,例:事务管理中,开启事务、提交事务、···
- 切面(Aspect):抽取功能增强的类就是切面类,例:事务管理器;在切面类中定义通知类(增强的功能)
- 切点(Pointcut):连接点中需要被增强的方法
- 织入(Weaving):将通知(增强的功能)动态添加到切点的过程就是织入
- 代理对象(Proxy):通过动态代理生成的具有增强功能的对象
通知
名称 | 标签 | 注解 | 说明 |
---|---|---|---|
前置通知 | <aop:before> | @Before | 在切入点方法之前执行 |
后置通知 | <aop:afterReturning> | @AfterReturning | 在切入点方法正常运行之后执行 |
异常通知 | <aop:afterThrowing> | @AfterThrowing | 在切点方法发生异常的时候执行 |
最终通知 | <aop:after> | @After | 无论切入点方法执行时是否有异常,都会执行 |
环绕通知 | <aop:around> | @Around | 可以灵活实现四大通知的所有效果 注意:通常情况下,环绕通知都是独立使用的 |
属性:
- method :指定通知中方法的名称
- pointct :定义切入点表达式
- pointcut-ref :指定切入点表达式的引用
基于XML的AOP
在spring的配置文件(applicationContext.xml)中进行配置,首先切面类需要有注解 @component
,如果没有需要在配置文件中Bean
一下配置
<!--AOP-->
<aop:config>
<!--切面-->
<aop:aspect id="切面类名" ref="切面类名">
<!--切点配置-->
<aop:pointcut id="aop" expression="execution(public void service.Service.*(..))"/>
<!--前置通知-->
<aop:before method="begin" pointcut-ref="aop"/>
<!--正常处理业务完成通知-->
<aop:after-returning method="commit" pointcut-ref="aop"/>
<!--异常通知-->
<aop:after-throwing method="rollback" pointcut-ref="aop"/>
<!--后置通知-->
<aop:after method="close" pointcut-ref="aop"/>
</aop:aspect>
</aop:config>
XML环绕通知
在切面中定义环绕方法
public Object around(ProceedingJoinPoint point) {
Object o = null;
begin();
try {
o = point.proceed();
commit();
} catch (Throwable e) {
rollback();
} finally {
close();
}
return o;
}
xml进行配置
<!--AOP-->
<aop:config>
<!--切面-->
<aop:aspect id="userTransactionManager" ref="userTransactionManager">
<!--切点配置-->
<aop:pointcut id="aop" expression="execution(public void service.Service.*(..))"/>
<!--环绕增强-->
<aop:around method="around" pointcut-ref="aop"/>
</aop:aspect>
</aop:config>
配值环绕增强之后,可以代替上面配置的四项增强
切点表达式
execution([修饰符] 返回类型 [全限定类名].方法名(参数列表)[异常列表])
修饰符:不写就是4个全包括 public、protected、private、default
返回类型:必写项,*
表示所有类型
全限定类名:选填项 ..表示当前包及子包下的所有类;*
表示当前包及子包下的所有类;不写表示所有类
方法名:必写项,*
表示所有方法;String *
表示以当前字符串开头的所有方法;如:set *
表示以set开头的所有方法
参数列表:必写项 ()表示没有参数的方法;(*
)表示只有一个参数的方法;(*
,string) 表示第一个参数随意,第二个参数是String类型的方法
基于注解的AOP
开启 spring 对注解 AOP 的支持:
<aop:aspectj-autoproxy/>
;也可以不加,使用注解也行在开发当中尽量不要同时使用注解的四大通知,特殊场景推荐使用:环绕通知
切面类:
@Component
// 切面类
@Aspect
public class UserTransactionManager {
// 前置通知
@Before("execution(* service.Service.*(..))")
public void begin() {
System.out.println("我开启了事务");
}
// 后置通知
@AfterReturning("execution(* service.Service.*(..))")
public void commit() {
System.out.println("我提交了事务");
}
// 异常通知
@AfterThrowing("execution(* service.Service.*(..))")
public void rollback() {
System.out.println("可能出错了,所以我回滚了事务");
}
// 最终通知
@After("execution(* service.Service.*(..))")
public void close() {
System.out.println("我关闭了事务");
}
/*
* 环绕通知
* 注意:如果配置了环绕通知那么上面的通知不会生效,所以两个配置其中的一种即可
* */
@Around("execution(* service.Service.*(..))")
public Object around(ProceedingJoinPoint point) {
Object o = null;
begin();
try {
o = point.proceed();
commit();
} catch (Throwable e) {
rollback();
} finally {
close();
}
return o;
}
}
上面的切点表达式可以进行简化,只需要轻易一个空方法方法上面加入注解 @Pointcut("execution(* service.Service.*(..))")
,到时候注解内只需要引入空方法名即可