
一、AOP 三大概念
Spring AOP 有三个重要的组成部分:Aspect、Pointcut、Advice。Advice 代表时间、Pointcut 代表位置,Aspect 代表代理方法
- Advice(通知/增强):在特定的连接点执行的代码,如前置通知、后置通知、环绕通知等
- Pointcut(切点):定义了通知应该在哪些连接点(方法)上生效
- Aspect(切面):一个模块化的横切关注点,通常是一个类,包含通知和切点
二、AOP 的实现方式
Spring AOP 的实现依赖于代理模式和动态代理技术。Spring 提供了两种主要的 AOP 实现方式:
- 基于 JDK 动态代理:适用于目标对象实现了接口的情况
- 基于 CGLIB 动态代理:适用于目标对象没有实现接口的情况
三、AOP 代理创建流程
3.1、 Bean 初始化
当你在 Spring 配置类中使用 @EnableAspectJAutoProxy 注解时,Spring 会导入 AspectJAutoProxyRegistrar 然后注册 AnnotationAwareAspectJAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor 接口,我们知道 BeanPostProcessor 是一个 Bean 声明周期接口,所以在 Spring 生成 Bean 的时候会调用 AnnotationAwareAspectJAutoProxyCreator 的 postProcessBeforeInstantiation 方法来检查当前 Bean 是否需要被代理
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 检查当前 Bean 是否需要被代理
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
3.2 wrapIfNecessary 方法
wrapIfNecessary 方法判断 Bean 是否需要创建代理。如果当前 Bean 有适用的增强器,则通过 createProxy 方法来实际创建代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
} else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
} else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
3.3 createProxy 方法
createProxy 方法会根据目标类是否实现了接口来决定使用 JDK 动态代理还是 CGLIB 动态代理,这样 Spring 生成的Bean 其实是经过 AOP 增强的 Bean
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
Class[] var6 = beanClass.getInterfaces();
int var7 = var6.length;
for(int var8 = 0; var8 < var7; ++var8) {
Class<?> ifc = var6[var8];
proxyFactory.addInterface(ifc);
}
}
} else if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
ClassLoader classLoader = this.getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader)classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
}
四、学习交流
链接: Java-AI学习交流
一个人的精力是有限的,没有那么多的时间去探索新的事物,加入一个交流群就相当于增加了一个接触新事物、新想法、新机会的渠道,这就是交流群存在的意义,期待你的加入!