spring-reading./spring-aop/spring-aop-proxyFactory/README.md

8.4 KiB
Raw Blame History

ProxyFactory

一、基本信息

✒️ 作者 - Lex 📝 博客 - 掘金 📚 源码地址 - github

二、基本描述

ProxyFactory类是Spring AOP中的关键组件之一用于动态创建代理对象并将切面逻辑织入到目标对象的方法调用中。通过设置目标对象、接口、通知等属性ProxyFactory提供了一种便捷的方式来创建代理对象,实现面向切面编程的功能。

三、主要功能

  1. 创建代理对象

    • 允许动态地创建代理对象,这些代理对象可以代表目标对象,并在方法调用前后执行额外的逻辑。
  2. 切面逻辑织入

    • 通过添加通知AdviceProxyFactory可以将切面逻辑织入到代理对象的方法调用中,实现横切关注点的处理。
  3. 支持接口代理和类代理

    • 支持基于接口的JDK动态代理和基于类的CGLIB代理可以根据需要选择合适的代理方式。
  4. 灵活的配置选项

    • 提供了丰富的配置选项,如设置目标对象、接口、通知、代理方式等,可以根据具体需求进行灵活配置。
  5. 简化AOP配置

    • 简化了AOP配置的过程通过简单的API调用即可实现代理对象的创建和切面逻辑的织入降低了AOP配置的复杂度。

四、类关系图

classDiagram
direction BT
class Advised {
<<Interface>>

}
class AdvisedSupport
class ProxyConfig
class ProxyCreatorSupport
class ProxyFactory
class TargetClassAware {
<<Interface>>

}

Advised  -->  TargetClassAware 
AdvisedSupport  ..>  Advised 
AdvisedSupport  -->  ProxyConfig 
ProxyCreatorSupport  -->  AdvisedSupport 
ProxyFactory  -->  ProxyCreatorSupport 

五、最佳实践

使用ProxyFactory类来创建代理对象并将前置通知MethodBeforeAdvice应用于目标对象的方法调用中。首先通过ProxyFactory创建代理工厂,并指定目标对象为MyService类的实例。然后,添加前置通知MyMethodBeforeAdvice到代理工厂中。接着,调用getProxy()方法获取代理对象,并将其存储在Object类型的变量中。最后,打印出代理对象的类名。

public class ProxyFactoryDemo {

    public static void main(String[] args) {
        // 创建代理工厂&创建目标对象
        ProxyFactory proxyFactory = new ProxyFactory(new MyService());
        // 创建通知
        proxyFactory.addAdvice(new MyMethodBeforeAdvice());
        // 获取代理对象
        Object proxy = proxyFactory.getProxy();
        // 调用代理对象的方法
        System.out.println("proxy = " + proxy.getClass());
    }
}

这个类可以作为一个目标对象,通过代理工厂创建代理对象,并在其方法调用前后应用额外的逻辑,实现面向切面编程的功能。

public class MyService {

}

运行结果表明代理对象是通过Spring的CGLIB动态代理生成的它是MyService类的一个增强版本。

proxy = class com.xcs.spring.MyService$$EnhancerBySpringCGLIB$$d9bdf44b

六、源码分析

初始化阶段

org.springframework.aop.framework.ProxyCreatorSupport#ProxyCreatorSupport()方法中,ProxyCreatorSupport类是ProxyFactory类的父类,因此当初始化ProxyFactory时,ProxyCreatorSupport也会跟着初始化,确保在创建代理对象时能够利用ProxyCreatorSupport的功能。在构造函数中,它初始化了aopProxyFactory成员变量,将其设置为一个DefaultAopProxyFactory对象用于后续创建AOP代理对象。

/**
 * 创建一个新的 ProxyCreatorSupport 实例。
 */
public ProxyCreatorSupport() {
    this.aopProxyFactory = new DefaultAopProxyFactory();
}

org.springframework.aop.framework.ProxyFactory#ProxyFactory(java.lang.Object)方法中,构造函数接受一个目标对象作为参数,并将其设置为要被代理的目标对象。然后,通过调用ClassUtils.getAllInterfaces(target)方法获取目标对象实现的所有接口,并将它们设置为代理工厂要代理的接口。

/**
 * 创建一个新的ProxyFactory。
 * <p>将代理目标对象实现的所有接口。
 * @param target 要被代理的目标对象
 */
public ProxyFactory(Object target) {
    setTarget(target);
    setInterfaces(ClassUtils.getAllInterfaces(target));
}

org.springframework.aop.framework.AdvisedSupport#setTarget方法中,它接受一个对象作为参数,并将该对象设置为代理工厂的目标对象。在内部,它会使用SingletonTargetSource来包装目标对象,以确保每次获取代理时都返回相同的目标对象实例。

/**
 * 将给定的对象设置为目标对象。
 * 将为该对象创建一个 SingletonTargetSource。
 * @see #setTargetSource
 * @see org.springframework.aop.target.SingletonTargetSource
 */
public void setTarget(Object target) {
    setTargetSource(new SingletonTargetSource(target));
}

org.springframework.aop.framework.AdvisedSupport#setInterfaces方法中,用于设置要被代理的接口。它接受一个可变参数interfaces,表示需要被代理的接口列表。在方法内部,首先通过Assert.notNull(interfaces, "Interfaces must not be null")断言确保传入的接口数组不为空。然后,清空当前ProxyFactory对象中已经设置的接口列表,并遍历传入的接口数组,逐个调用addInterface(ifc)方法将接口添加到接口列表中。这样做是为了确保在创建代理对象时,只代理指定的接口。

/**
 * 设置要被代理的接口。
 */
public void setInterfaces(Class<?>... interfaces) {
    Assert.notNull(interfaces, "Interfaces must not be null");
    this.interfaces.clear();
    for (Class<?> ifc : interfaces) {
        addInterface(ifc);
    }
}

创建代理阶段

org.springframework.aop.framework.ProxyFactory#getProxy()方法中,根据工厂中的配置创建一个新的代理对象。可以重复调用此方法,根据已添加或删除的接口以及添加或移除的拦截器的不同,其效果会有所变化。该方法会使用默认的类加载器,通常是线程上下文类加载器(如果需要代理创建时)。最终返回创建的代理对象。

AopProxy源码分析

/**
 * 根据该工厂中的设置创建一个新的代理对象。
 * <p>可以重复调用。如果已添加或删除接口,则效果会有所不同。可以添加和删除拦截器。
 * <p>使用默认的类加载器:通常是线程上下文类加载器(如果需要创建代理)。
 * @return 代理对象
 */
public Object getProxy() {
    return createAopProxy().getProxy();
}

org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy方法中,首先检查active标志,如果当前ProxyFactory对象未激活,则调用activate()方法进行激活。然后,通过调用getAopProxyFactory().createAopProxy(this)来获取AOP代理对象的工厂并使用当前ProxyFactory对象作为参数来创建AOP代理。最终返回创建的AOP代理对象。

AopProxyFactory源码分析

/**
 * 子类应调用此方法以获取一个新的AOP代理。它们不应该使用 {@code this} 作为参数创建AOP代理。
 */
protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

七、常见问题

  1. 代理对象的类型问题

    • 有时候可能会出现代理对象的类型不符合预期的情况比如期望使用JDK动态代理但实际上使用了CGLIB代理或者代理对象的类名不符合预期。
  2. AOP通知未生效

    • 可能会出现AOP通知未生效的情况这可能是由于配置错误、通知未添加到代理工厂中或者代理对象未正确调用等原因引起的。