zoukankan      html  css  js  c++  java
  • SpringAOP[4]代理工厂

    序:代理对象的创建

    无论是AspecJProxyFactoryProxyFactoryBeanProxyFactory大体逻辑都是:

    1. 填充ProxyCreatorSupport,实际上它是Advised子类,即填充代理配置类(添加Advisor、添加Advice)
    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博客
  • 相关阅读:
    添加一个用户到指定用户组: gpasswd –a 用户名 组名 usermod –G 组名 用户名
    MySQL创建用户和授权
    shell
    启动脚本
    TODO
    mysql表分区
    mysql导入千万级数据实操
    mysql快速保存插入大量数据一些方法总结(转)
    MySQL存储过程插入数据过慢处理方法(转)
    mysql备份删库建库导入库
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15559345.html
Copyright © 2011-2022 走看看