ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringAOP[4]-代理工厂

2021-11-16 03:31:35  阅读:189  来源: 互联网

标签:TService advice 代理 工厂 对象 Advisor SpringAOP new public


序:代理对象的创建

无论是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博客

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:TService,advice,代理,工厂,对象,Advisor,SpringAOP,new,public
来源: https://www.cnblogs.com/chenxingyang/p/15559345.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有