zoukankan      html  css  js  c++  java
  • SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator

    本文将对SpringAop中如何为AspectJ切面类创建自动代理的过程作下简单的分析,阅读本文前需要对AOP的Spring相关解析有所了解,具体可见Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器

    官方注释

    注释内容如下

    /**
     * {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}
     * subclass that exposes AspectJ's invocation context and understands AspectJ's rules
     * for advice precedence when multiple pieces of advice come from the same aspect.
     *
     * @author Adrian Colyer
     * @author Juergen Hoeller
     * @author Ramnivas Laddad
     * @since 2.0
     */
    

    从注释上可知此类是org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator抽象类的继承类,主要为AspectJ切面服务。具体的针对如何创建代理,肯定是在父类中实现了,我们在此研究下父类。

    AbstractAutoProxyCreator-AOP代理实现的抽象父类

    继承结构上为extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware,而其中的SmartInstantiationAwareBeanPostProcessor是beanPostProcessor接口的子类,此处注意下此接口。下面分析的内容建立在spring在实例化bean对象的时候会调用beanPostProcessor的公有接口。

    AbstractAutoProxyCreator#postProcessAfterInitialization()-创建代理的入口函数

    先奉上源码内容如下

    	/**
    	 * Create a proxy with the configured interceptors if the bean is
    	 * identified as one to proxy by the subclass.
    	 * @see #getAdvicesAndAdvisorsForBean
    	 */
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		if (bean != null) {
    			Object cacheKey = getCacheKey(bean.getClass(), beanName);
    			// 如果缓存中不存在则调用wrapIfNecessary()方法创建代理
    			if (!this.earlyProxyReferences.contains(cacheKey)) {
    				return wrapIfNecessary(bean, beanName, cacheKey);
    			}
    		}
    		return bean;
    	}
    

    以上调用的是beanPostProcessor接口的postProcessAfterInitialization(Object bean,String beanName)的方法,其一般是bean对象被实例化的最后一步操作的,此处避而不谈了,我们转而查看wrapIfNecessary()的内部是如何操作的

    AbstractAutoProxyCreator#wrapIfNecessary()-创建代理对象帮助函数

    	/**
    	 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
    	 * @param bean the raw bean instance
    	 * @param beanName the name of the bean
    	 * @param cacheKey the cache key for metadata access
    	 * @return a proxy wrapping the bean, or the raw bean instance as-is
    	 */
    	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    	    // 查看缓存是否存在此bean
    		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
    			return bean;
    		}
    		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    			return bean;
    		}
    		// Advice/Advisor/AopInfrastructureBean接口的beanClass不进行代理以及对beanName为aop内的切面名也不进行代理,此处可查看子类复写的sholdSkip()方法
    		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    			this.advisedBeans.put(cacheKey, Boolean.FALSE);
    			return bean;
    		}
    
    		// Create proxy if we have advice.
    		// 查找对代理类相关的advisor对象集合,此处就与ponit-cut表达式有关了
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		// 对相应的advisor不为空才采取代理
    		if (specificInterceptors != DO_NOT_PROXY) {
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
    			// 调用createProxy()方法创建真正的代理对象
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    
    		this.advisedBeans.put(cacheKey, Boolean.FALSE);
    		return bean;
    	
    

    对上述的源码分析作下简单的总结

    1. 首先对Advice/Advisor/AopInfrastructureBean接口的实现类不进行代理操作;对beanName为aspectName的bean对象也不采取代理操作

    2. 再而需要查找beanClass有几个advisor与之相关联,这当然与每个Advisor接口内的PointCut对象对应的表达式expression有关。只有关联的Advisor个数不为0,才可采取代理(此处查找Advisor关联个数的源码读者可自行分析AspectJAwareAdvisorAutoProxyCreator#shouldSkip()方法)

    3. 真正的代理操作是由AbstractAutoProxyCreator#createProxy()内部方法实现

    AbstractAutoProxyCreator#createProxy()-创建真正的AOP代理

    对符合条件的beanClass进行相应的代理操作,简单看下源码

    	/**
    	 * Create an AOP proxy for the given bean.
    	 * @param beanClass the class of the bean
    	 * @param beanName the name of the bean
    	 * @param specificInterceptors the set of interceptors that is
    	 * specific to this bean (may be empty, but not null)
    	 * @param targetSource the TargetSource for the proxy,
    	 * already pre-configured to access the bean
    	 * @return the AOP proxy for the bean
    	 * @see #buildAdvisors
    	 */
    	protected Object createProxy(
    			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
    		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    		}
    		// 创建AOP代理工厂,拷贝相同的属性
    		ProxyFactory proxyFactory = new ProxyFactory();
    		proxyFactory.copyFrom(this);
    		// 是否采用动态代理
    		if (!proxyFactory.isProxyTargetClass()) {
    			if (shouldProxyTargetClass(beanClass, beanName)) {
    				proxyFactory.setProxyTargetClass(true);
    			}
    			else {
    				// 查看beanClass对应的类是否含有InitializingBean.class/DisposableBean.class/Aware.class接口,无则采用静态代理,有则采用动态代理
    				evaluateProxyInterfaces(beanClass, proxyFactory);
    			}
    		}
    		// 获得所有关联的Advisor集合
    		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    		for (Advisor advisor : advisors) {
    			proxyFactory.addAdvisor(advisor);
    		}
    		// 此处的targetSource一般为SingletonTargetSource
    		proxyFactory.setTargetSource(targetSource);
    		customizeProxyFactory(proxyFactory);
    
    		proxyFactory.setFrozen(this.freezeProxy);
    		// 是否设置预过滤模式,此处针对本文为true
    		if (advisorsPreFiltered()) {
    			proxyFactory.setPreFiltered(true);
    		}
    
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}
    

    对以上的源码也作下简单的总结

    1. 采用ProxyFactory对象来创建代理对象

    2. 如果AOP没有指定proxyTargetClass属性,则针对beanClass含有非InitializingBean/DisposableBean/Aware接口的bean采用静态代理,反之采用动态代理

    3. ProxyFactory创建代理对象前也需要设置与beanClass相关联的advisor集合

    ProxyFactory#getProxy()-最终创建代理类

    public Object getProxy(ClassLoader classLoader) {
    		return createAopProxy().getProxy(classLoader);
    	}
    

    以上的源码我们只需要关注createAopProxy()方法即可,此处我们直接查看DefaultAopProxyFactory#createAopProxy()源码,参考如下

    	@Override
    	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    		if (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.");
    			}
    			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}
    

    上述源码很简单,默认是采用JDK静态代理,对beanClass为非接口实现类采取CGLIB动态代理

    小结

    • 循序渐进的分析的总结见以上的各部分小结,我们只需要知道AOP代理的beanClass必须有相应的Advisor接口与之绑定,才会创建AOP代理

    • 创建的代理类无非是JDK代理抑或是CGLIB代理,但是具体关联的Advisor集合的处理逻辑见下文讲解

  • 相关阅读:
    牛客网分糖果
    【bzoj3717】[PA2014]Pakowanie 状压dp
    【bzoj1042】[HAOI2008]硬币购物 背包dp+容斥原理
    [POI2007]堆积木Klo
    【bzoj5018】[Snoi2017]英雄联盟 背包dp
    BZOJ 1492 [NOI2007]
    bzoj 2741 [FOTILE模拟赛] L
    bzoj 1486 最小圈
    计数
    cf 700
  • 原文地址:https://www.cnblogs.com/question-sky/p/7788931.html
Copyright © 2011-2022 走看看