AOP
AOP 概述
- AOP 即面向切面编程
- AOP 采取横向抽取机制
- AOP 使用动态代理实现
AOP 原理
public class User {
public void addUser() {
// TODO
}
}
// 扩展功能:添加日志功能(什么时候添加的用户)
// 方案一
直接在 TODO 中修改源代码,添加日志逻辑
// 方案二 纵向抽取机制
public class BaseUser {
public void writeLog() {
// TODO
}
}
public class User extend BaseUser{
public void addUser() {
// TODO
// 调用父类方法实现日志功能
super.writeLog();
// 当父类方法名改变,仍然需要修改源代码
}
}
// 方案三 横向抽取机制(AOP)
// 情况一(有接口)
public interface Dao {
public void addUser();
}
public class DaoImpl implements Dao {
public void addUser() {
// TODO 旧逻辑
}
}
// 使用动态代理的方式创建接口实现类的代理对象
// 即创建与 DaoImpl 类的平级对象,增强旧逻辑功能
// 实现与 DaoImpl 相同的功能
// Jdk 动态代理
// 情况二 无接口
// 没有接口情况,同样使用动态代理
// 使用子类的代理对象调用父类的方法完成增强
// Cglib 动态代理
AOP 操作术语
public class User {
public void add() {
}
public void update() {
}
public void findAll() {
}
}
- Joinpiont(连接点)
可以被增强的方法,如 add()等
- Pointcut(切入点)
实际被增强的方法
- Adcice(通知/增强)
即扩展(增强)的功能(逻辑)
- 前置通知:方法之前执行
- 后置通知:方法之后执行
- 异常通知:方法出现异常时执行
- 最终通知:后置之后执行
- 环绕通知:方法之前之后都执行
前置-> 环绕-> 后置 -> 最终
- Aspect(切面)
把增强应用到方法上称之为切面
- Introduction(引介)
可以用于动态添加属性或方法
- Target(目标对象)
增强逻辑所在的类
- Weaving(织入)
增强的过程
- Proxy(代理)
织入后的类称之为代理类
AOP 操作
使用 Aspect 框架实现
只有 Spring 2.x 以上支持
准备
- 导入 Jar 包
- aopalliance
- aspectjweaver
- spring-aop
- spring-sepects
- 添加约束
- aop
- spring-aop
使用表达式配置切入点
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
例如:
execution(* xin.jeson.User.show(..)) // 增强 User 类中的show方法
execution(* xin.jeson.User.*(..)) // 增强 User 类中的所有方法
execution(* *.*(..)) // 增强所有类中的所有方法
execution(* xx*(..)) // 增强所有 xx 开头的方法
使用 Aspect 实现 AOP 的两种方式
- xml 配置文件进行增强
// 需要被增强的类
public class User {
public void show() {
System.out.println("User");
}
}
// 增强逻辑的类
public class MyUser {
// 前置通知
public void beforeShow() {
System.out.println("Before");
}
// 后置通知
public void afterShow() {
System.out.println("After");
}
// 环绕通知
public void aroundShow(proceedingJoinPoint proceedingJoinPoint) {
// 方法之前
System.out.println("BeforeByAround");
// 执行被增强的方法
proceedingJoinPoint.proceed();
// 方法之后
System.out.println("AfterByAround");
}
}
<!-- 配置对象 -->
<bean id="user" class="xin.jeson.User"/>
<bean id="myUser" class="xin.jeson.MyUser"/>
<!-- 配置 AOP 操作 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* xin.jeson.User.*(..))" id="pointcut"/>
<!-- 配置切面 -->
<aop:aspect ref="myUser">
<!-- 将 myUser 中的方法配置到切入点 -->
<aop:before method="beforeShow" pointcut-ref="pointcut"/>
<aop:after-returning method="afterShow" pointcut-ref="pointcut"/>
<aop:around method="aroundShow" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
- 使用注解进行 AOP 操作
<!-- 开启 AOP 操作 -->
<aop:aspectj-autoproxy/>
// 需要被增强的类
@Component(value="user")
public class User {
public void show() {
System.out.println("User");
}
}
// 增强逻辑的类
@Component(value="myUser")
@Aspect
public class MyUser {
// 前置通知
@Before(value="execution(* xin.jeson.User.show(..))")
public void beforeShow() {
System.out.println("Before");
}
// 后置通知
@AfterReturning(value="execution(* xin.jeson.User.show(..))")
public void afterShow() {
System.out.println("After");
}
// 环绕通知
@Around(value="execution(* xin.jeson.User.show(..))")
public void aroundShow(proceedingJoinPoint proceedingJoinPoint) {
// 方法之前
System.out.println("BeforeByAround");
// 执行被增强的方法
proceedingJoinPoint.proceed();
// 方法之后
System.out.println("AfterByAround");
}
// @After 最终通知
}