一、Spring AOP是什么
- AOP:面向切面,是一种编程思想,OOP的延续。
- 将系统中非核心的业务提取出来,进行单独处理。比如事务、日志和安全等。这个简单来说就是可以在一段程序之前或者之后做一些事。
二、代理对象的创建过程:
AbstractAutowireCapableBeanFactory#initializeBean
protectedObjectinitializeBean(StringbeanName,Objectbean,@NullableRootBeanDefinitionmbd){
if(System.getSecurityManager()!=null){
AccessController.doPrivileged((PrivilegedAction<Object>)()->{
invokeAwareMethods(beanName,bean);
return null;
},getAccessControlContext());
}
else{
invokeAwareMethods(beanName,bean);
}
ObjectwrappedBean=bean;
if(mbd==null||!mbd.isSynthetic()){
// 执⾏所有的BeanPostProcessor#postProcessBeforeInitialization 初始化之前
的处理器⽅法
wrappedBean=applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
}
try{
// 这⾥就开始执⾏afterPropertiesSet(实现了InitializingBean接⼝)⽅法和
initMethod
invokeInitMethods(beanName,wrappedBean,mbd);
}
catch(Throwableex){
thrownewBeanCreationException((mbd!=null? mbd.getResourceDescription():null),beanName,"Invocationofinitmethodfailed",ex);
}
if(mbd==null||!mbd.isSynthetic()){
// 整个Bean初始化完成,执⾏后置处理器⽅法
wrappedBean=applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);
}
return wrappedBean;
}
可以看到有初始化前执行的方法、初始化时执行的方法、初始化之后执行的方法,我们从初始化之后执行的方法入手。
三、applyBeanPostProcessorsAfterInitialization
applyBeanPostProcessorsAfterInitialization()方法的流程如下:

简要流程:

详细流程:
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
->AbstractAutoProxyCreator#postProcessAfterInitialization
(1)创建代理Bean:applyBeanPostProcessorsAfterInitialization中会检查下该类是否已经暴露过了(可能已经创建了,⽐如A依赖B时,创建A时候,就会先去创建B。当真正需要创建B时,就没必要再代理⼀次已经代理过的对象),避免重复创建。
->AbstractAutoProxyCreator#wrapIfNecessary
(2)获取适用于当前类的Advisor:得到所有候选Advisor(切点),对Advisors和bean的⽅法双层遍历匹配,最终得到⼀个List<Advisor>,即specificInterceptors,指对这个bean进行操作的切点
->AbstractAutoProxyCreator#createProxy
(3)创建代理:
A、创建代理的⼯作交给ProxyFactory
B、把指定和通⽤拦截对象合并, 并都适配成Advisor
C、上⾯准备做完就开始创建代理
->proxyFactory.getProxy()
(4)依据是否是接口,判断使用jdk还是cglib:⽤ProxyFactory创建AopProxy, 然后⽤AopProxy创建Proxy, 所以这⾥重要的是看获取的AopProxy对象是什么,然后进去看怎么创建动态代理, 提供了两种:jdk proxy, cglib
四、Aop的jdk和cglib怎么实现?有什么工作区别
4-1)JDK 动态代理
4-1-1)基于接口:JDK 动态代理要求目标类必须实现至少一个接口。
4-1-2)代理对象生成:在运行时,通过 java.lang.reflect.Proxy 类动态生成代理类。
代理类会实现目标类的接口,并重写接口中的方法。
通过 InvocationHandler 接口的 invoke 方法实现增强逻辑。
4-2)CGLIB 代理
4-2-1)基于继承:CGLIB 通过生成目标类的子类来实现代理。
4-2-2)代理对象生成:使用 ASM 字节码操作框架动态生成目标类的子类。重写父类方法,并在方法中插入增强逻辑。代理类会覆盖父类的非 final 方法。
4-3)Spring 中如何选择代理方式
4-3-1)默认行为:
如果目标类实现了接口,Spring 默认使用 JDK 动态代理。
如果目标类没有实现接口,Spring 使用 CGLIB 代理。
4-3-2)强制使用 CGLIB:
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB
4-3-3)性能考量:
在低版本 Spring 中,CGLIB 生成代理较慢,但调用更快;JDK 代理生成快,调用慢。
在高版本 Spring 和 JDK 中,两者性能差距已不明显。
五、Spring aop在什么场景下会失效
AOP失效的场景:
1)静态方法调用:静态方法不属于对象,因此无法通过代理对象调用,AOP无法拦截。Spring AOP 基于动态代理,无法拦截静态方法。
2)final方法:final方法无法被覆盖,因此无法通过子类化实现代理,AOP无法拦截。CGLIB 代理通过生成子类实现,无法覆盖私有方法和 final 方法。
3)私有方法调用:私有方法只能在类内部调用,无法通过代理对象调用,AOP不会生效。
4)自调用:当一个方法在同一个类中自调用时,AOP同样不会生效。Spring AOP 通过代理对象调用方法,而内部调用绕过代理直接访问目标对象。Spring AOP 通过代理对象调用方法,而内部调用绕过代理直接访问目标对象。
备注:
1)如何利用aop切面实现多数据源切换
1-1)配置多数据源:在 application.yml 中定义多个数据源(如主库、从库)
1-2)定义动态数据源路由类:继承 AbstractRoutingDataSource,通过 ThreadLocal 保存当前线程的数据源标识:
1-3)定义数据源切换注解:创建 @DataSource 注解,用于标记方法或类应使用的数据源
1-4)配置数据源 Bean 和动态路由:在 Spring 配置类中注册数据源,并将动态路由设为默认数据源
1-5)创建 AOP 切面实现数据源切换:通过切面拦截 @DataSource 注解,动态切换数据源
1-6)使用:在 Service 方法上标注 @DataSource,指定数据源
2)Spring的上下文怎么存储?
2-1)Bean定义:通过 BeanDefinitionRegistry 存储为Map。
2-2)Bean实例:单例Bean缓存于 ConcurrentHashMap,原型Bean每次重新创建。
2-3)依赖管理:三级缓存解决循环依赖。
2-4)环境配置:Environment 管理多属性源。
2-5)AOP代理:代理对象覆盖原始Bean存储。
2-6)层级结构:父子上下文独立存储,子可访问父。
更多内容:
Spring篇(1)--SpringBoot是什么?原理是怎么样的?
Spring篇(4-1)--Spring Bean 是什么及其生命周期阶段
本文介绍了Spring AOP的基本概念及其实现原理,重点解析了AOP在Spring中的代理对象创建过程,包括Bean的初始化前后所触发的一系列操作,以及如何通过BeanPostProcessor创建代理Bean。





