Spring AOP 源码剖析

一.AOP基础概念 

  1. 切面(Aspect):切面是跨越多个类的关注点模块化,如事务管理。切面由切点和通知组成。
  2. 连接点(Join Point):在程序执行过程中某个特定的点,如方法调用或异常抛出。在Spring AOP中,连接点通常是方法的执行点。
  3. 切点(Pointcut):用于定义哪些连接点会被增强/通知。切点表达式决定了通知被应用到哪些具体的方法上。
  4. 通知(Advice):在切面的某个特定连接点上执行的动作。通知类型包括前置通知、后置通知、返回通知、异常通知和环绕通知。
  5. 织入(Weaving):将切面应用到目标对象并创建代理对象的过程。Spring AOP是在运行时通过动态代理完成织入的。
  6. 引入(Introduction):允许向现有的类添加新方法或属性。

二.Spring AOP源码实现机制

概念:

Spring AOP主要通过动态代理技术实现,包括JDK动态代理和CGLIB代理。对于实现了接口的类,Spring默认使用JDK动态代理;对于没有实现接口的类,则使用CGLIB生成子类作为代理。

1. 代理对象的生成

代理对象的生成通常发生在Bean的初始化后阶段,由BeanPostProcessor接口的实现类(如AnnotationAwareAspectJAutoProxyCreator)负责。这个类会在Bean初始化后检查是否需要为Bean生成代理对象。如果需要,它会根据配置和Bean的类型选择合适的代理技术(JDK或CGLIB),并创建代理对象。

2. 代理方法的执行

当代理对象的方法被调用时,Spring AOP会根据配置的通知类型和切点表达式,决定在方法执行的前、后或抛出异常时执行哪些通知。这通常通过一个“责任链”模式实现,责任链中的每个节点代表一个通知,按照配置的顺序依次执行。

对于环绕通知,它会包裹目标方法的调用,在调用前后执行自定义的逻辑。环绕通知提供了最大的灵活性,因为它可以控制目标方法的执行流程(例如,可以决定是否继续执行目标方法)。

2.1源码分析

Spring AOP 主要基于两种⽅式实现的: JDK 及 CGLIB 的⽅式
Spring对于AOP的实现,基本上都是靠 AnnotationAwareAspectJAutoProxyCreator 去完成
⽣成代理对象的逻辑在⽗类 AbstractAutoProxyCreator
    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);

        /**
         * 检查proxyTargetClass属性值,spring默认为false
         * proxyTargetClass 检查接⼝是否对类代理, ⽽不是对接⼝代理
         * 如果代理对象为类, 设置为true, 使⽤cglib代理
         */
        if (!proxyFactory.isProxyTargetClass()) {
            //是否有设置cglib代理
            if (shouldProxyTargetClass(beanClass, beanName)) {
                //设置proxyTargetClass为true,使⽤cglib代理
                proxyFactory.setProxyTargetClass(true);
            } else {
                /**
                 * 如果beanClass实现了接⼝,且接⼝⾄少有⼀个⾃定义⽅法,则使⽤JDK代理
                 * 否则CGLIB代理(设置ProxyTargetClass为true )
                 * 即使我们配置了proxyTargetClass=false, 经过这⾥的⼀些判断还是可能会将其
                 设为true
                 */
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
        // Use original ClassLoader if bean class not locally loaded in overriding
        class loader
 ClassLoader classLoader = getProxyClassLoader();
        if (classLoader instanceof SmartClassLoader && classLoader !=
                beanClass.getClassLoader()) {
            classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
        }
        //从代理⼯⼚中获取代理
    }
    return proxyFactory.getProxy(classLoader);
            }
代理⼯⼚有⼀个重要的属性: proxyTargetClass, 默认值为false. 也可以通过程序设置
可以通过 @EnableAspectJAutoProxy(proxyTargetClass = true
Spring Boot 2.X开始, 默认使⽤CGLIB代理
可以通过配置项 spring.aop.proxy-target-class=false 来进⾏修改,设置默认为jdk代理
SpringBoot设置 @EnableAspectJAutoProxy ⽆效, 因为Spring Boot 默认使AopAutoConfiguration进⾏装配
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context =
                SpringApplication.run(DemoApplication.class, args);
        /**
         * HouseProxy houseProxy = context.getBean(HouseProxy.class);
         * 设置spring.aop.proxy-target-class=true cglib代理, 运⾏成功
         * 设置spring.aop.proxy-target-class=false jdk代理, 运⾏失败, 不能代理类
         * 因为 HouseProxy 是⼀个类, ⽽不是接⼝, 需要修改为
         * HouseSubject houseProxy = (HouseSubject) 
         context.getBean("realHouseSubject")
         *
         */
        HouseProxy houseProxy = context.getBean(HouseProxy.class);
        //HouseSubject houseProxy = (HouseSubject) 
        context.getBean("realHouseSubject");//正确运⾏
        System.out.println(houseProxy.getClass().toString());
    }
}
使⽤context.getBean() 需要添加注解,使HouseProxy,RealHouseSubject被Spring管理
测试AOP代理, 需要把这些类交给AOP管理(⾃定义注解或使⽤@Aspect)
点进去看代理⼯⼚的代码
public class ProxyFactory extends ProxyCreatorSupport {
 //...代码省略
 //获取代理
 public Object getProxy(@Nullable ClassLoader classLoader) {
 //分两步 先createAopProxy,后getProxy
 return createAopProxy().getProxy(classLoader);
 }
 
 protected final synchronized AopProxy createAopProxy() {
 if (!this.active) {
 activate();
 }
 return getAopProxyFactory().createAopProxy(this);
 }
 //...代码省略
}
createAopProxy的实现在 DefaultAopProxyFactory中
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
 //...代码省略
 @Override
 public AopProxy createAopProxy(AdvisedSupport config) throws
AopConfigException {
 /**
 * 根据proxyTargetClass判断
 * 如果⽬标类是接⼝, 使⽤JDK动态代理
 * 否则使⽤cglib动态代理
 */
 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.");
 }
 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || 
ClassUtils.isLambdaClass(targetClass)) {
 return new JdkDynamicAopProxy(config);
 }
 return new ObjenesisCglibAopProxy(config);
 }
 else {
 
 return new JdkDynamicAopProxy(config);
  }
 }
 //...代码省略
}
接下来就是创建代理了
JDK动态代理
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, 
Serializable {
 //...代码省略
 @Override
 public Object getProxy(@Nullable ClassLoader classLoader) {
 if (logger.isTraceEnabled()) {
 logger.trace("Creating JDK dynamic proxy: " + 
this.advised.getTargetSource());
 }
 return Proxy.newProxyInstance(determineClassLoader(classLoader), 
this.proxiedInterfaces, this);
 }
 //...代码省略
}
CGLIB动态代理
class CglibAopProxy implements AopProxy, Serializable {
 //...代码省略
 @Override
 public Object getProxy(@Nullable ClassLoader classLoader) {

 //...代码省略
 
 // Configure CGLIB Enhancer...
 Enhancer enhancer = createEnhancer();
 
 // Generate the proxy class and create a proxy instance.
 return createProxyClassAndInstance(enhancer, callbacks);
 
 }
 //...代码省略
}

 总结:

Spring AOP通过动态代理技术提供了一种灵活的方式来增强现有方法的功能,而无需修改源代码。其源码实现涉及Bean生命周期管理、动态代理技术、责任链模式等多个方面,深入理解这些机制有助于更好地使用和维护Spring AOP。

请注意,由于Spring框架的不断发展,源码实现细节可能会有所变化。因此,在实际分析源码时,建议参考最新的Spring文档和源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值