什么是AOP
AOP(面向切面)编程,是一种编程思想;是对面向对象编程OOP的一种增强,OOP是纵向对一个事物的抽象。而AOP是横向的对不同事物的抽象、抽取,而用这种思维去设计编程的方式叫做面向切面编程。
相关概念
-
Target(目标对象)
- 需要被增强的方法所在的对象
-
Proxy(代理对象)
- 对目标对象进行增强后的对象
-
Joinpoint(连接点)
- 目标对象中 可以 被增强的方法
-
Pointcut(切入点)
- 目标对象中 实际 被增强的方法
-
Advice(通知/增强)
- 增强部分的代码逻辑
-
Aspect(切面)
- 增强部分和切入点的组合
-
Weaving(织入)
- 将通知和切入点动态组合的过程
上图所示是一个AOP的架构,现有一个 目标对象 A,对象A中有三个方法可以被增强,也就是说有三个 连接点 ;现在想要增强的方法是methodA1、methodA2,所以这两个方法就是 切入点 ;我们要使用对象B中的两个方法做一个增强,所以methodB1、methodB2就是 增强 的具体代码;最后我们将切点与增强的代码组合在一起就形成了一个 切面 并存储到代理对象的具体方法中。现在通过调用代理对象的方法就可以执行增强后的methodA1、methodA2。
在Spring中通过注解实现AOP
导入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
在配置类中添加@EnableAspectJAutoProxy注解
@Configuration
@ComponentScan("com.demo")
@EnableAspectJAutoProxy //开启切面自动代理(开启AOP功能)
public class SpringConfig {}
目标对象
@Component
public class User {
@Autowired
private Pets pets;
//切入点
void petEat(){
pets.eat();
}
}
定义切面、编写增强方法、配置切入点
@Component
@Aspect //定义切面
public class MyAspect {
//配置切入点 @Before:前置增强
@Before(value = "execution(* com.demo.User.petEat(..))")
public void sayHello(){ //编写增强方法
System.out.println("hello");
}
}
运行结果
hello
大黄开始吃东西了
AOP运行原理
- @EnableAspectJAutoProxy注解会导入AspectJAutoProxyRegistrar
@EnableAspectJAutoProxy //开启切面自动代理(开启AOP功能)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
-
紧接着会注册一个AnnotationAwareAspectJAutoProxyCreator到容器中,继承体系中包含BeanPostProcessor后处理器,在 postProcessAfterInitialization 中筛选出需要被增强的bean,创建代理对象
BeanPostProcessor后处理器:后处理器postProcessAfterInitialization方法,会在Bean创建实例并初始化之后,填充到单例池singletonObjects之前执行。在这个阶段可以对指定的对象进行扩展。
动态代理的两种方式
-
JDK动态代理
- 使用条件:目标类有接口,实现原理是基于接口动态生成实现类的代理对象
- 在spring中,如果目标类有接口,默认使用JDK动态代理
-
Cglib动态代理
- 使用条件:目标类没有接口并且不能使用final修饰,实现原理是基于被代理对象动态生成子对象为代理对象
- 在spring中,目标类如果没有接口,默认使用Cglib动态代理。
- 强制使用:如果目标类有接口,仍需使用Cglib,可以通过配置proxy-target-class="true"强制使用
@EnableAspectJAutoProxy(proxyTargetClass = true)