AOP(Aspect Oriented Programming)是一种面向切面的编程思想
Spring AOP 作为Spring最核心的能力之一,基于动态代理,允许开发者定义切面并插入横切关注点,通过AOP我们可以将一些通用代码(如日志记录、权限判断等)和业务代码分离开,使得我们的业务代码更加专注于业务逻辑的处理
Spring AOP实现
AOP的使用方式相对简单(这里基于注解方式)
自定义注解
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OptStatus {
//自定义注解
}
在需要增强的方法上加入我们自定义的注解
java
@OptStatus
public void queryList(String OrderQuery) {
//业务代码
...
...
}
创建其对应的切面
java
@Slf4j
@Aspect
@Component
public class PageStatusAspect {
//声明要进行代理的注解
@Pointcut("@annotation(com.apec.order.aop.annotation.OptStatus)")
public void pointCut() {
}
/**
*
* @param joinPoint
* @return
*/
@SneakyThrows
@Around("pointCut()")
public Object PageStatusDecoration(ProceedingJoinPoint joinPoint) {
//业务代码
...
...
}
}
实现不是本文的重点(网上有很多),在这里就随便提一下(ps:如果需要具体的案例,后面再出相应的文章)
Spring AOP源码解析
spring aop基于动态代理,那么spring会在bean初始化的时候,为目标对象创建代理对象放到容器中,后续我们在调用目标方法的时候,我们就会拿到代理对象,从而通过代理对象调用目标对象方法
创建代理对象
initializeBean()
bean初始化方法,主要包含以下内容:
- Bean Aware方法回调
- BeanPostProcessor 初始化前回调
- 执行初始化方法
- BeanPostProcessor 初始化后回调
java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 如果存在SecurityManager,执行相应的安全代码
if (System.getSecurityManager() != null) {
// ...
}
else {
// 如果bean实现了特定的Aware接口(如BeanNameAware, BeanFactoryAware等),则调用相应的方法
invokeAwareMethods(beanName, bean);
}
// 初始化前的预处理,调用所有BeanPostProcessors的postProcessBeforeInitialization方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用bean的初始化方法,例如afterPropertiesSet和custom init-method
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
// ...
}
// 初始化后的后处理,调用所有BeanPostProcessors的postProcessAfterInitialization方法(包含了AOP代理后置处理器)
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
// 返回最终的bean实例,可能被AOP代理等包装
return wrappedBean;
}
先看一下applyBeanPostProcessorsAfterInitialization()
方法源码
java
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
// 保存原始Bean对象
Object result = existingBean;
// 如果有回调函数 返回null,使用原始的Bean对象,否则使用返回值作为当前Bean对象
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
为什么说applyBeanPostProcessorsAfterInitialization()
方法完成了AOP动态代理?
这里我们先了解一下这个类BeanPostProcessor
,它提供 Spring Bean 初始化前和初始化后的生命周期回调,允许对关心的 Bean 进行扩展,甚至是替换
在后置处理器中有一个AbstractAutoProxyCreator
后置处理器
顾名思义这个类就是用来构建spring bean的代理对象的,它里面有一个createProxy()
方法,在这个方法中会通过代理工厂proxyFactory.getProxy(classLoader)
来创建代理对象,主要看createAopProxy()
和getProxy()
方法
java
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
我们都知道spring aop提供了两种代理方式JDK动态代理和CGLIB代理,bean 使用哪一种代理方式呢?就由createAopProxy()
方法决定
java
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 目标类是一个接口,则使用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用CGLIB代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 根据配置使用JDK动态代理 配置项spring.aop.proxy-target-class
return new JdkDynamicAopProxy(config);
}
}
前面已经确定了使用哪一种代理模式,getProxy()
方法就是获取对应的代理对象(基本上就是JDK动态代理和CGLIB代理的原理,这里就不多说了)
- 如果想了解JDK动态代理可以看我这篇文章:彻底搞懂JDK动态代理
- 如果想了解CGLIB代理可以看我这篇文章:彻底搞懂CGLIB代理
调用目标对象
当用户调用目标对象的某个方法时,实际会调用代理对象的invoke()
方法,在这个方法中会调用MethodInvocation
的proceed()
方法(按顺序执行符合所有AOP拦截规则的拦截器链),每一种Aspect(前置、后置、环绕、异常)都是一个MethodInvocation
类。

在MethodInterceptor
的invoke()
方法中会触发对目标对象方法的调用,也就是(ReflectiveMethodInvocation
)反射调用目标对象的方法

总结
Spring AOP 提供了两种代理方式JDK动态代理和CGLIB代理(根据目标类来选择其中一种)
在通过使用@EnableAspectJAutoProxy
注解开启AOP后,会向spring容器中注入一个后置处理器AbstractAutoProxyCreator
,在bean初始化后,对需要代理的目标对象,生成代理对象。 当用户调用目标对象的某个方法时,通过MethodInterceptor
的invoke()
方法中会触发对目标对象方法的调用