回顾SpringAOP的实现原理

本文详细解析面向切面编程(AOP)中的织入机制,包括编译期、类加载期及运行时织入的不同方式,并重点介绍了运行时织入的具体实现逻辑。文章对比了静态代理、JDK动态代理与Cglib动态代理的区别,还探讨了Spring框架如何选择合适的代理方式,并提供了SpringBoot中强制使用Cglib动态代理的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 概述

面向切面编程的织入时机

1. 编译期织入(AspectJ)

2. 类加载加载织入(AspectJ 5+)

3. 运行时(Spring AOP)

二 运行时织入的实现逻辑

代理对象的交互图

如图,客户端是通过代理对象间接的同目标对象进行交互,换言之,目标对象委托了代理对象同客户端进行交互。

根据类图可知,客户端通过接口来对目标对象或代理对象进行引用,这里就涉及了一个很重要的原则,面向接口编程,这时候就涉及到两个重要的结论:

1. 因为客户端调用的真正对象的方法,代理类都要有。所以代理对象和调用对象都要作为该接口的实现类。

2. 代理对象会将方法委托给真正的对象进行执行,而代理类就执行一些额外的逻辑,即AOP织入的逻辑。

运行时织入是通过代理对象,代理可以分为了两种:静态代理和动态代理。

其中动态代理又分为基于接口代理和基于继承代理实现,这两类的代表为JDK代理与CGlib代理。

三 运行时织入之静态代理的实现

接口类

public interface IA {

    void getName();
}

接口实际实现类

public class RealIA implements IA{

    @Override
    public void getName() {
        System.out.println("真正对象实现请求!");
    }
}

接口代理类

public class ProxyIA implements IA{

    //代理对象需要委托真正对象去完成一些逻辑
    private RealIA realIA;

    //强制
    public ProxyIA(RealIA realIA) {
        this.realIA = realIA;
    }

    //代理对象不会实现真是的逻辑
    @Override
    public void getName() {

        //类似于AOP的before,after,around
        //代理对象完成其他逻辑
        System.out.println("before代理逻辑");

        //代理对象委托真正的对象来完成客户端逻辑
        try {
            realIA.getName();
        } catch (Exception e) {
            System.out.println("ex:" + e.getMessage());
            throw e;
        } finally {
            System.out.println("after代理逻辑");
        }
    }
}

由上述静态代理的实现可知,当接口中方法越多,需要实现的代理方法越多时,重复的逻辑就越多。

四 运行时织入之JDK动态代理

1. JDK代理需要通过java.lang.reflect.Proxy类来动态生成代理类

2. 代理类需要实现织入逻辑需要实现接口InvocationHandler

3. JDK动态代理只能基于接口进行动态代理

JDK动态代理代码实现

JDK动态代理类

public class JdkProxySubject implements InvocationHandler {

    private RealIA realIA;

    public JdkProxySubject(RealIA realIA) {
        this.realIA = realIA;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //织入的逻辑
        System.out.println("before代理");

        Object result = null;
        try{
            //通过invoke方法执行动态代理的逻辑
            //Method通过应用反射机制,来动态反射方法
            result = method.invoke(realIA,args);
        }catch (Exception e){

        }finally {
            //织入的逻辑
            System.out.println("after代理");
        }
        return result;
    }
}

JDK动态代理客户端

public class JdkClient {

    public static void main(String[] args) {
        IA ia = (IA) Proxy.newProxyInstance(JdkClient.class.getClassLoader(),
                new Class[]{IA.class},new JdkProxySubject(new RealIA()));
        ia.getName();
    }
}

结合上面的IA接口和RealIA实现类,就完成了JDK动态代理的实例。

五 运行时织入之JDK动态代理底层逻辑

根据实例代码可知JDK动态代理的代码生成,先通过Proxy.newProxyInstance方法,接着调用一次通过方法getProxyClass0,ProxyClassFactory,ProxyGenerator方法实现动态代理的代码的生成 ,这个过程生成的代码时字节码,最后通过Java的反射机制new出实例代码。

newProxyInstance方法源码

 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

        //寻找或者生成指定代理类
        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);
}

getProxyClass0方法源码

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        //如果缓存中存在代码,则getProxyClass0方法先从缓存中获取代码,如果没有就会通过ProxyClassFactory进行创建并放入缓存
        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

缓存源码

 proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

ProxyClassFactory方法源码

    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {

                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                //接口的类 
                Class<?> interfaceClass = null;
                try {
                    //找到接口类
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
}

代理类名称格式

   /*
    * Choose a name for the proxy class to generate.
    */
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

根据源码可知,代理类的最后名称中包含long类型的数字字符。

六 运行时织入之CGlib动态代理

Cglib动态代理类

public class IAInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("before in cglib");
            Object result = null;
            try{
                result = methodProxy.invokeSuper(o,objects);
            }catch (Exception e){
                System.out.println(e.getMessage());
            }finally {
                System.out.println("after in cglib");
            }
            return result;
    }
}

Cglib动态代理客户端类

public class CglibClient {

    public static void main(String[] args) {
        //Cglib的增强对象
        Enhancer enhancer = new Enhancer();
        //设置增强类型,增强真是对象
        enhancer.setSuperclass(RealIA.class);
        enhancer.setCallback(new IAInterceptor());
        IA ia = (IA) enhancer.create();
        ia.getName();
    }
}

基于静态代理的接口IA真正实现类RealIA来实现的代码实例 。

七 JDK动态代理和Cglib动态代理之间的区别

1. JDK动态代理时基于接口实现的动态代理,对接口中的方法进行代理织入代码。

2. Cglib动态代理是基于继承实现的动态代理,所以实现Static和final类进行代理。

3. 同因为Cglib动态代理是基于继承实现的动态代理,所以无法完成Static和private方法的代理。

4. 因为接口中方法不可以是private方法,所以JDK动态代理也无法完成private方法的代理。

八 Spring创建代理bean的方法

对于动态代理而言,同时存在JDK动态代理和Cglib动态代理两种。

根据Spring创建代理类的时序图可得,先由AbstractAutoProxyCreator类调用createProxy方法返回代理类。

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {	
    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 (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				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);
		}

		return proxyFactory.getProxy(getProxyClassLoader());
	}
}

而createProxy方法又是调用ProxyFactory来生成的,然而createProxy方法又是委托给ProxyCreatorSupport类来生成。

public class ProxyCreatorSupport extends AdvisedSupport {
    protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}
}

最后ProxyCreatorSupport又是通过DefaultAopProxyFactory来实现的。

public class ProxyCreatorSupport extends AdvisedSupport {
    public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}
}

DefaultAopProxyFactory实现createAopProxy生成代理类的方法。

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	/**
	 * Whether this environment lives within a native image.
	 * Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
	 * @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
	 */
	private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!IN_NATIVE_IMAGE &&
				(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)) {
				return new JdkDynamicAopProxy(config);
			}
            //Cglib动态代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
            //使用JDK动态代理
			return new JdkDynamicAopProxy(config);
		}
	}
}

根据源码可知,Spring中只有两种情况使用JDK动态代理,其他的情况都是使用Cglib动态代理。

根据上述源码可知,当目标对象实现了接口的情况下,默认使用的JDK动态代理,而没有实现接口的情况下,则使用的是Cglib动态代理,当然在目标对象实现了接口的情况下,但是强制使用Cglib动态代理的情况下,还是会通过Cglib动态代理。

九 SpringBoot中强制使用CGlib动态代理的方法

@SpringBootApplication
//强制使用Cglib动态代理
public class SpringaopApplication {

    public static void main(String[] args) { SpringApplication.run(SpringaopApplication.class, args); }
}

根据实例代码可知通过注解@EnableAspectJAutoProxy(proxyTargetClass = true)可以强制使用Cglib动态代理。

这样做的原理的使得if (!IN_NATIVE_IMAGE && (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)))判断条件中的config.isProxyTargetClass()为true。

<think>好的,用户想了解Spring AOP的原理,特别是代理模式、动态代理和静态代理。首先,我需要回顾一下代理模式的基本概念,然后区分静态代理和动态代理的不同,再联系到Spring AOP是如何应用这些技术的。 首先,代理模式的定义。根据引用[1],代理模式允许在不修改被代理对象的情况下,通过代理类进行功能增强。这里的关键是代理类分为静态和动态两种。静态代理需要手动创建代理类,而动态代理在运行时生成。用户可能想知道这两种代理在Spring AOP中的应用场景。 接下来,静态代理的细节。引用[1]提到静态代理的类在运行前已经存在,通常由程序员手动编写或工具生成。例如,假设有一个业务接口Subject和实现类RealSubject,静态代理类Proxy实现Subject并持有RealSubject的引用,在方法调用前后添加逻辑。这种情况的缺点是每个被代理类都需要一个对应的代理类,导致代码冗余。 然后是动态代理,Spring AOP主要使用JDK动态代理和CGLIB。引用[2]指出JDK代理通过Proxy类生成代理对象,而CGLIB通过Enhancer创建。JDK动态代理要求目标类实现接口,利用InvocationHandler的invoke方法进行增强。CGLIB则通过继承目标类,重写方法来实现代理,适用于没有接口的情况。需要解释这两种方式的区别以及Spring如何选择使用哪一种。 还要结合Spring AOP的源码,如引用[2]提到的AOP源码剖析部分。Spring在运行时决定使用哪种代理方式,如果目标类实现了接口,默认使用JDK代理,否则使用CGLIB。这涉及到AOP的配置和底层机制。 用户可能还关心AOP的应用场景,比如事务管理、日志记录等,这些通过代理模式实现,无需修改原有代码。需要举例说明,比如在方法执行前后加事务控制,动态代理如何拦截方法调用并添加额外操作。 另外,需要确保回答结构清晰,分点说明原理、代理类型、实现方式以及Spring的选择策略。同时,生成的相关问题要围绕用户可能进一步询问的点,比如性能比较、配置方法或实际应用例子。 最后,检查引用是否正确应用,如引用[1]关于代理模式的分类,引用[2]关于Spring AOP的具体实现,引用[3]关于代理模式的角色。确保每个技术点都有对应的引用支持,增加回答的可信度。</think>### Spring AOP原理与代理模式解析 #### 一、代理模式的核心作用 代理模式通过代理对象控制对真实对象的访问,在**不修改原始代码**的前提下实现功能增强。其核心角色包括: - **Subject**:定义业务接口(可以是接口或抽象类)[^3] - **RealSubject**:具体业务实现类(被代理对象) - **Proxy**:代理类,负责增强和控制对RealSubject的访问 #### 二、静态代理的实现方式 静态代理需**手动编写代理类**,代理关系在编译时确定。例如: ```java // 业务接口 interface UserService { void save(); } // 真实对象 class UserServiceImpl implements UserService { public void save() { /* 业务逻辑 */ } } // 静态代理类 class UserServiceProxy implements UserService { private UserService target; public UserServiceProxy(UserService target) { this.target = target; } public void save() { System.out.println("前置增强"); target.save(); // 调用真实对象方法 System.out.println("后置增强"); } } ``` **缺点**:每个业务类需对应一个代理类,代码冗余度高[^1]。 #### 三、动态代理的实现机制 Spring AOP主要采用两种动态代理技术: 1. **JDK动态代理**(基于接口) - 要求目标类必须实现至少一个接口 - 通过`java.lang.reflect.Proxy`生成代理对象 - 核心类`InvocationHandler`实现方法拦截: ```java class JdkProxyHandler implements InvocationHandler { private Object target; public Object getProxy(Object target) { this.target = target; return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) { System.out.println("前置增强"); Object result = method.invoke(target, args); System.out.println("后置增强"); return result; } } ``` 2. **CGLIB代理**(基于继承) - 通过生成目标类的子类实现代理 - 使用`MethodInterceptor`接口: ```java class CglibInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { System.out.println("前置增强"); Object result = proxy.invokeSuper(obj, args); System.out.println("后置增强"); return result; } } // 通过Enhancer创建代理 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); enhancer.setCallback(new CglibInterceptor()); TargetClass proxy = (TargetClass)enhancer.create(); ``` - **优势**:可代理无接口的类[^2] #### 四、Spring AOP的代理选择策略 | 条件 | 使用的代理方式 | |--------------------------|----------------| | 目标类实现了至少一个接口 | JDK动态代理 | | 目标类未实现任何接口 | CGLIB代理 | **底层实现**: - 通过`DefaultAopProxyFactory`类判断代理方式 - Spring Boot 2.x后默认强制使用CGLIB(可通过`spring.aop.proxy-target-class=true`配置) #### 五、AOP核心流程 1. 解析切面定义(@Aspect) 2. 匹配连接点(Pointcut) 3. 生成代理对象 4. 编增强逻辑(Advice) 5. 通过责任链模式执行拦截器链 #### 六、性能对比 - **JDK动态代理**:生成速度快,执行效率稍低 - **CGLIB**:生成速度慢,执行效率高(现代JVM差距已不明显)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值