Java教程

SpringAOP[4]-代理工厂

本文主要是介绍SpringAOP[4]-代理工厂,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

序:代理对象的创建

无论是AspecJProxyFactoryProxyFactoryBeanProxyFactory大体逻辑都是:

  1. 填充ProxyCreatorSupport,实际上它是Advised子类,即填充代理配置类;
  2. 得到JDK或者CGLIB的AopProxy;
  3. Proxy Bean被调用时,被invoke或intercept方法拦截,并且会调用ProxyCreatorSupport(AdvisedSupport)getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各个方法上的拦截器链并缓存

上述三个类本身并没有什么关系,但是都继承自ProxyCreatorSupport,创建代理对象的核心就是在ProxyCreatorSupport中实现的。

一、通过ProxyFactoryBean配置

FactoryBean目的是构建复杂的Bean对象,而ProxyFactoryBeangetObject()最终产生的便是Proxy Bean。

配置类:

@Configuration
public class MyConfig {
    @Bean
    public LogMethodBeforeAdvice logMethodBeforeAdvice() {
        return new LogMethodBeforeAdvice();
    }

    @Bean("tService")
    public TService tService() {
        return new TService();
    }

    @Bean("proxyFactoryBean")
    public ProxyFactoryBean proxyFactoryBean(TService tService) {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        //代理的目标对象,效果等效于setTargetSource()
        proxyFactoryBean.setTarget(tService);
        //设置`String[] interceptorNames`,以便后续初始化"拦截器链"。
        proxyFactoryBean.setInterceptorNames("logMethodBeforeAdvice");
        return proxyFactoryBean;
    }
}

拦截器类:

public class LogMethodBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("this is logMethodBeforeAdvice!");
    }
}

目标类:

public class TService {
    public void run1(){
        System.out.println("This is a run1() Method!");
    }
}

测试类:

public class TestProxy {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        //可以使用@Primary指定元素,或直接使用name名获取。
        //Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException:
        // No qualifying bean of type 'com.tellme.Impl.proxy.TService' available:
        // expected single matching bean but found 2: tService,proxyFactoryBean。(或生成两个Bean名字)
        //TService bean = applicationContext.getBean(TService.class);
        //若使用Class获取Bean,会获取到两个Bean对象。
        TService bean = (TService)applicationContext.getBean("proxyFactoryBean");
        bean.run1();
        System.out.println(bean.getClass());
    }
}

结果:

this is logMethodBeforeAdvice!
This is a run1() Method!
class com.tellme.Impl.proxy.TService$$EnhancerBySpringCGLIB$$6ac1bfc1

 

如测试案例所示,构建ProxyFactoryBean的过程实际上是完成的是代理配置。即填充Advised对象。而Advised对象实际上是由多个Advisor组成。

ProxyFactoryBean便是借助于控制反转,只是传入Interceptors类名便完成拦截对象的填充。

ProxyFactoryBean实际上实现的是FactoryBean接口,那么产生的Bean是getObject方法返回的。而getObject便完成代理对象的创建过程。


1.1 初始化AdvisorChain

代理对象的创建,首先要创建配置对象,即实现Advised接口,Spring实现了该接口。我们最终通过ProxyCreatorSupport提供的API便可以完成配置

 配置Advised,实际上执行的是initializeAdvisorChain()

  1. 在IOC容器中通过BeanName获取到Advice对象,(当然这种情况属于单例,而Spring作为一个框架,实际上会考虑原型模式以及通配符的情况)。
  2. 借助AdvisorAdapterRegistryAdvice转换为Advisor(当然pointcut是Pointcut.TRUE,拦截所有的方法)。
  3. Advisor加入到AdvicedSupport维护的列表中。该代理对象会持有所有的Advisor
public class ProxyFactoryBean extends ProxyCreatorSupport
        implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {

    /** Whether the advisor chain has already been initialized. */
    private boolean advisorChainInitialized = false;

    //(步骤1:获取代理对象)
    @Override
    @Nullable
    public Object getObject() throws BeansException {
        //初始化AdvisorChain。
        initializeAdvisorChain();
        if (isSingleton()) {
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }
    //(步骤2:初始化过滤器链)
    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        //若拦截器链已经初始化,直接跳出。
        if (this.advisorChainInitialized) {
            return;
        }
        //该变量实际上是由proxyFactoryBean.setInterceptorNames("logMethodBeforeAdvice");设置的
        if (!ObjectUtils.isEmpty(this.interceptorNames)) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
            }

            // Globals can't be last unless we specified a targetSource using the property...
            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
                throw new AopConfigException("Target required after globals");
            }

            // Materialize interceptor chain from bean names.
            for (String name : this.interceptorNames) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Configuring advisor or advice '" + name + "'");
                }
              //若是拦截器名字以*结尾,要全局搜索出来(相当于一个批量处理)
              //最终依旧会调用addAdvisorOnChainCreation加入到单例池中。
                if (name.endsWith(GLOBAL_SUFFIX)) {
                    if (!(this.beanFactory instanceof ListableBeanFactory)) {
                        throw new AopConfigException(
                                "Can only use global advisors or interceptors with a ListableBeanFactory");
                    }
                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                }

                else {
                    // If we get here, we need to add a named interceptor.
                    // We must check if it's a singleton or prototype.
                    Object advice;
                    if (this.singleton || this.beanFactory.isSingleton(name)) {
                        // Add the real Advisor/Advice to the chain.
                        //若是拦截器为单例,那么在单例池中获取单例对象
                        advice = this.beanFactory.getBean(name);
                    }
                    else {
                        // It's a prototype Advice or Advisor: replace with a prototype.
                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                        //若是多例,每次均产生一个拦截器对象
                        advice = new PrototypePlaceholderAdvisor(name);
                    }
                    //将获取到的拦截器对象加入到拦截器链中。
                    addAdvisorOnChainCreation(advice, name);
                }
            }
        }
        //设置标识为true。
        this.advisorChainInitialized = true;
    }
    //(步骤3:将advice转转化为Advisor)
    private void addAdvisorOnChainCreation(Object next, String name) {
        // We need to convert to an Advisor if necessary so that our source reference
        // matches what we find from superclass interceptors.
        Advisor advisor = namedBeanToAdvisor(next);
        if (logger.isTraceEnabled()) {
            logger.trace("Adding advisor with name '" + name + "'");
        }
      //将Advisor加入到Advised的配置列表中
        addAdvisor(advisor);
    }
    //(步骤4:转换为Advisor)
    private Advisor namedBeanToAdvisor(Object next) {
        try {
            return this.advisorAdapterRegistry.wrap(next);
        }
        catch (UnknownAdviceTypeException ex) {
            throw new AopConfigException("Unknown advisor type " + next.getClass() +
                    "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
                    "which may also be target or TargetSource", ex);
        }
    }

}

 

实际上执行的是wrap()方法

上述是实际上是通过DefaultPointcutAdvisor(advice)将advice转换为了增强器Advisor。Pointcut使用的是Pointcut.TRUE,即拦截target中所有的Method
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }
}

调用addAdvisor(advisor);是将Advisor加入到AdvisedSupport维护的List<Advisor>中。创建出的代理对象会包含Advised的配置。

 

2 获取代理对象

源码:org.springframework.aop.framework.ProxyFactoryBean#getObject

public Object getObject() throws BeansException {  
    //初始化AdvisorChain(此时我们在这...)
    initializeAdvisorChain();  
    if (isSingleton()) {  
        //返回单例对象。
        return getSingletonInstance();  
    }  
    else {  
        if (this.targetName == null) {  
            logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +  
                    "Enable prototype proxies by setting the 'targetName' property.");  
        }  
        return newPrototypeInstance();  
    }  
}  
private synchronized Object getSingletonInstance() {  
    if (this.singletonInstance == null) {  
    //根据设置的targetName,去单例池中获取bean对象
        this.targetSource = freshTargetSource();  
        //这一步是如果你手动没有去设置需要被代理的接口,Spring还是会去帮你找看你有没有实现啥接口,然后全部给你代理上。可见Spring的容错性是很强的
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {  
            // Rely on AOP infrastructure to tell us what interfaces to proxy.  
            Class<?> targetClass = getTargetClass();  
            if (targetClass == null) {  
                throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");  
            }  
            //Spring自动寻找接口,并且设置接口
            setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));  
        }  
        // Initialize the shared singleton instance.  
        super.setFrozen(this.freezeProxy);  
        //创建代理对象。
        this.singletonInstance = getProxy(createAopProxy());  
    }  
    return this.singletonInstance;  
}  
//返回代理对象
protected Object getProxy(AopProxy aopProxy) {  
    //实际上是调用的AopProxy对象创建的代理对象。
    return aopProxy.getProxy(this.proxyClassLoader);  
}  

 

1. 2. 脱离IOC容器使用

public class ProxyFactoryBeanDemo {
    public static void main(String[] args) {
        String pointcutExpression = "execution (void com.tellme.Impl.proxy.TService.run1())";
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(new TService());
        //设置切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(pointcutExpression);
        Advice advice=(MethodInterceptor) invocation -> {
            System.out.println("请求before...");
            Object obj = invocation.proceed();
            System.out.println("请求after...");
            return obj;
        };
        //创建Advisor
        Advisor advisor=new DefaultPointcutAdvisor(pointcut,advice);
        //加入到Advised过滤器链中
        proxyFactoryBean.addAdvisor(advisor);
        //获取代理对象
        TService service = (TService)proxyFactoryBean.getObject();
        service.run1();
        System.out.println(service.toString());
    }
}

借助IOC容器,实际上做两件事情:

  • 初始化AdvisorChain,根据传入的proxyFactoryBean.setInterceptorNames("");去IOC容器中获取Advice对象。
  • 根据Advised配置,创建Proxy对象。

最后都借助于getProxy(createAopProxy())产生代理对象。所以PoxyFactoryBean可以不借助于IOC执行。


二、 通过AspectJProxyFactory配置

@Aspect
public class MyAspect {
    @Pointcut("execution (void com.tellme.Impl.proxy.TService.run1())")
    private void beforeAdd(){
    }
    @Before("beforeAdd()")
    public void before1(){
        System.out.println("---------before----------");
    }
}
public class Demo {
    public static void main(String[] args) {
        AspectJProxyFactory proxyFactory=new AspectJProxyFactory(new TService());
        proxyFactory.addAspect(MyAspect.class);
        TService bean =proxyFactory.getProxy();
        bean.run1();
    }
}

我们传入MyAspect类,便自动完成了代理。

  • 需要注意的是:使用AspectjProxyFactory基于切面类创建代理对象时,我们指定的切面类必须包含@Aspect注解。

  • 虽然我们自己可以通过编程的方式可以通过AspectjProxyFactory创建基于@Aspect切面类的代理类,但是通过<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)使用基于注解的AspectJ风格的AOP时,Spring内部不是通过AspectjProxyFactory创建的代理对象,而是通过ProxyFactory。

【小家Spring】面向切面编程Spring AOP创建代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory(JDK Proxy和CGLIB)_Java方向盘-CSDN博客

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于SpringAOP[4]-代理工厂的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!