Spring源码分析——AOP

  • Post author:
  • Post category:其他




Spring源码分析——AOP



寻找 aop:aspectj-autoproxy 注解对应的解析器

要使用SpringAop的功能,需要在XMl配置文件中配置 <aop:aspectj-autoproxy/>注解,这个注解便是开启spring的aop功能的开关,所以他就是分析aop功能原理的入口

org.springframework.aop.config.AopNamespaceHandler#init

	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.5+ XSDs
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		/**
		 * 注册自定义的BeanDefinition解析器,用于自定义 "节点解析成BeanDefinition" 的流程
		 * AspectJAutoProxyBeanDefinitionParser主要的功能就
		 * 是将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中,
		 * 把bean交给Spring去托管
		 */
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
	<span class="token comment">// Only in 2.0 XSD: moved to context namespace in 2.5+</span>
	<span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">"spring-configured"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">SpringConfiguredBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

可以看到,我们只要配置了<aop:aspectj-autoproxy/>注解,其实就会想spring容器中注册一个BeanDefinition解析器 AspectJAutoProxyBeanDefinitionParser,BeanDefinition解析器的功能就是想spring容器中解析注册BeanDefinition的,然后spring就会根据已有的BeanDefinition取实例化bean



了解AspectJAutoProxyBeanDefinitionParser对应的行为

org.springframework.aop.config.AspectJAutoProxyBeanDefinitionParser#parse

	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//注册 AnnotationAwareAspectJAutoProxyCreator 对应的的BeanDefinition
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		extendBeanDefinition(element, parserContext);
		return null;
	}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里调用了AopNamespaceUtils的静态方法registerAspectJAnnotationAutoProxyCreatorIfNecessary

org.springframework.aop.config.AopNamespaceUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary

	public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
	BeanDefinition beanDefinition <span class="token operator">=</span> AopConfigUtils<span class="token punctuation">.</span><span class="token function">registerAspectJAnnotationAutoProxyCreatorIfNecessary</span><span class="token punctuation">(</span>
			parserContext<span class="token punctuation">.</span><span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> parserContext<span class="token punctuation">.</span><span class="token function">extractSource</span><span class="token punctuation">(</span>sourceElement<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">useClassProxyingIfNecessary</span><span class="token punctuation">(</span>parserContext<span class="token punctuation">.</span><span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> sourceElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">registerComponentIfNecessary</span><span class="token punctuation">(</span>beanDefinition<span class="token punctuation">,</span> parserContext<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到,这里又接着调用另外一个静态方法的AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法

org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
	<span class="token keyword">return</span> <span class="token function">registerOrEscalateApcAsRequired</span><span class="token punctuation">(</span>AnnotationAwareAspectJAutoProxyCreator<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> registry<span class="token punctuation">,</span> source<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired

	@Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
	Assert<span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span>registry<span class="token punctuation">,</span> <span class="token string">"BeanDefinitionRegistry must not be null"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token keyword">if</span> <span class="token punctuation">(</span>registry<span class="token punctuation">.</span><span class="token function">containsBeanDefinition</span><span class="token punctuation">(</span>AUTO_PROXY_CREATOR_BEAN_NAME<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		BeanDefinition apcDefinition <span class="token operator">=</span> registry<span class="token punctuation">.</span><span class="token function">getBeanDefinition</span><span class="token punctuation">(</span>AUTO_PROXY_CREATOR_BEAN_NAME<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>cls<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>apcDefinition<span class="token punctuation">.</span><span class="token function">getBeanClassName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token keyword">int</span> currentPriority <span class="token operator">=</span> <span class="token function">findPriorityForClass</span><span class="token punctuation">(</span>apcDefinition<span class="token punctuation">.</span><span class="token function">getBeanClassName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token keyword">int</span> requiredPriority <span class="token operator">=</span> <span class="token function">findPriorityForClass</span><span class="token punctuation">(</span>cls<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>currentPriority <span class="token operator">&lt;</span> requiredPriority<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
				apcDefinition<span class="token punctuation">.</span><span class="token function">setBeanClassName</span><span class="token punctuation">(</span>cls<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">return</span> null<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>

	<span class="token comment">/*创建AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinition */</span>
	RootBeanDefinition beanDefinition <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RootBeanDefinition</span><span class="token punctuation">(</span>cls<span class="token punctuation">)</span><span class="token punctuation">;</span>
	beanDefinition<span class="token punctuation">.</span><span class="token function">setSource</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">;</span>
	beanDefinition<span class="token punctuation">.</span><span class="token function">getPropertyValues</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"order"</span><span class="token punctuation">,</span> Ordered<span class="token punctuation">.</span>HIGHEST_PRECEDENCE<span class="token punctuation">)</span><span class="token punctuation">;</span>
	beanDefinition<span class="token punctuation">.</span><span class="token function">setRole</span><span class="token punctuation">(</span>BeanDefinition<span class="token punctuation">.</span>ROLE_INFRASTRUCTURE<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">/*注册AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinition*/</span>
	registry<span class="token punctuation">.</span><span class="token function">registerBeanDefinition</span><span class="token punctuation">(</span>AUTO_PROXY_CREATOR_BEAN_NAME<span class="token punctuation">,</span> beanDefinition<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> beanDefinition<span class="token punctuation">;</span>
<span class="token punctuation">}</span>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

到这一步,就可以看到创建AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinition并且注册该beanDefinition的处理,然后AnnotationAwareAspectJAutoProxyCreator的BeanDefinition就交给了spring容器管理了



分析AnnotationAwareAspectJAutoProxyCreator主要行为

AnnotationAwareAspectJAutoProxyCreator是AbstractAutoProxyCreator的子孙类,而AbstractAutoProxyCreator又实现了接口SmartInstantiationAwareBeanPostProcessor,

SmartInstantiationAwareBeanPostProcessor接口继承了InstantiationAwareBeanPostProcessor,而InstantiationAwareBeanPostProcessor又间接继承了BeanPostProcessor,所以可以认为AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor,因此它是一个bean后置处理器

而bean后置处理器的方法会在bean进行实例化回调的这个阶段被执行

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

	/**
	 * 如果bean被子类标识为要代理的bean,则使用配置的拦截器创建代理。
	 * 这个方法时重写BeanPostProcesser接口的方法
	 * 会在Bean完成初始化回调方法调用执行
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			/* 判断之前是否代理过 */
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				/* 在bean初始化之后对生产出的bean进行包装 */
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

postProcessAfterInitialization方法会在进行完bean的初始化回调方法后被执行,这里判断之前是否代理过,如果不是,就调用wrapIfNecessary进行代理

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}
	<span class="token comment">// 如果该类有advice则创建proxy.</span>
	Object<span class="token punctuation">[</span><span class="token punctuation">]</span> specificInterceptors <span class="token operator">=</span> <span class="token function">getAdvicesAndAdvisorsForBean</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> null<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>specificInterceptors <span class="token operator">!=</span> DO_NOT_PROXY<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> Boolean<span class="token punctuation">.</span>TRUE<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">/* 创建代理对象 */</span>
		Object proxy <span class="token operator">=</span> <span class="token function">createProxy</span><span class="token punctuation">(</span>
				bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> specificInterceptors<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">SingletonTargetSource</span><span class="token punctuation">(</span>bean<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>proxyTypes<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> proxy<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">/* 返回代理对象 */</span>
		<span class="token keyword">return</span> proxy<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>

	<span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> Boolean<span class="token punctuation">.</span>FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> bean<span class="token punctuation">;</span>
<span class="token punctuation">}</span>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

所以可以这么理解,一旦我们开启了aop的注解,那么在spring中创建的每个bean,在进行bean后置处理器的postProcessAfterInitialization回调的时候,都会被拿去校验是否方法作为作为joinPoint被某个切面的pointCut所切中,是的话就要进行代理返回代理对象。



创建proxy过程分析

上面如果判断要进行代理对象的创建时,就会通过createProxy创建代理对象,把该bean重新包装为代理对象proxy

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>beanFactory <span class="token keyword">instanceof</span> <span class="token class-name">ConfigurableListableBeanFactory</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		AutoProxyUtils<span class="token punctuation">.</span><span class="token function">exposeTargetClass</span><span class="token punctuation">(</span><span class="token punctuation">(</span>ConfigurableListableBeanFactory<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>beanFactory<span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> beanClass<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 1.创建proxyFactory,proxy的生产主要就是在proxyFactory做的</span>
	ProxyFactory proxyFactory <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProxyFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	proxyFactory<span class="token punctuation">.</span><span class="token function">copyFrom</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>proxyFactory<span class="token punctuation">.</span><span class="token function">isProxyTargetClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">shouldProxyTargetClass</span><span class="token punctuation">(</span>beanClass<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			proxyFactory<span class="token punctuation">.</span><span class="token function">setProxyTargetClass</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
			<span class="token function">evaluateProxyInterfaces</span><span class="token punctuation">(</span>beanClass<span class="token punctuation">,</span> proxyFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 2.将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中</span>
	Advisor<span class="token punctuation">[</span><span class="token punctuation">]</span> advisors <span class="token operator">=</span> <span class="token function">buildAdvisors</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> specificInterceptors<span class="token punctuation">)</span><span class="token punctuation">;</span>
	proxyFactory<span class="token punctuation">.</span><span class="token function">addAdvisors</span><span class="token punctuation">(</span>advisors<span class="token punctuation">)</span><span class="token punctuation">;</span>
	proxyFactory<span class="token punctuation">.</span><span class="token function">setTargetSource</span><span class="token punctuation">(</span>targetSource<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">customizeProxyFactory</span><span class="token punctuation">(</span>proxyFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

	proxyFactory<span class="token punctuation">.</span><span class="token function">setFrozen</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>freezeProxy<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">advisorsPreFiltered</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		proxyFactory<span class="token punctuation">.</span><span class="token function">setPreFiltered</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 3.调用getProxy获取bean对应的proxy</span>
	<span class="token keyword">return</span> proxyFactory<span class="token punctuation">.</span><span class="token function">getProxy</span><span class="token punctuation">(</span><span class="token function">getProxyClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

上面方法主要分三步

  1. 创建proxyFactory,用于创建代理对象
  2. 将当前bean适合的advice封装为Advisor类,然后添加到ProxyFactory中
  3. 调用getProxy获取bean对应的proxy

org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)

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

 
 
  • 1
  • 2
  • 3

org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy

	/**
	 * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
	 * create an AOP proxy with {@code this} as an argument.
	 *
	 * createAopProxy()方法就是决定究竟创建何种类型的proxy JDKProxy or CGLIBProxy
	 */
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		// 关键方法createAopProxy()
		return getAopProxyFactory().createAopProxy(this);
	}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

createAopProxy就会进行创建代理类的工作,后面就会通过这个代理类获取代理对象

org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// config.isOptimize()是否使用优化的代理策略,目前使用与CGLIB
		// config.isProxyTargetClass() 是否目标类本身被代理而不是目标类的接口
		// hasNoUserSuppliedProxyInterfaces()是否存在代理接口
		if (!IN_NATIVE_IMAGE &&
				(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)) {
				// 2.如果目标类是接口或者是代理类,则直接使用JDKproxy
				return new JdkDynamicAopProxy(config);
			}
			// 3.其他情况则使用CGLIBproxy
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

可以看到上面有两种情况

  • 如果要代理的对象是接口或者实现了某接口,则是由jdk动态代理
  • 普通类则使用CGLIB

我们看一下jdk动态代理的处理



JdkDynamicAopProxy.getProxy()方法

org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		// JDK proxy 动态代理的标准用法
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可以看到上面是jdk动态代理获取代理对象的标准用法

然后JdkDynamicAopProxy本身实现了Jdk动态代理要求实现的InvocationHandler

接口,所有肯定有Invoke方法

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

 
 
  • 1



invoke()方法

以上的代码模式可以很明确的看出来,使用了JDK动态代理模式,真正的方法执行在invoke()方法里

org.springframework.aop.framework.JdkDynamicAopProxy#invoke

	@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
	TargetSource targetSource <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>advised<span class="token punctuation">.</span>targetSource<span class="token punctuation">;</span>
	Object target <span class="token operator">=</span> null<span class="token punctuation">;</span>

	<span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
		<span class="token comment">// 1.以下的几个判断,主要是为了判断method是否为equals、hashCode等Object的方法</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>equalsDefined <span class="token operator">&amp;&amp;</span> AopUtils<span class="token punctuation">.</span><span class="token function">isEqualsMethod</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// The target does not implement the equals(Object) method itself.</span>
			<span class="token keyword">return</span> <span class="token function">equals</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>hashCodeDefined <span class="token operator">&amp;&amp;</span> AopUtils<span class="token punctuation">.</span><span class="token function">isHashCodeMethod</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// The target does not implement the hashCode() method itself.</span>
			<span class="token keyword">return</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> DecoratingProxy<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// There is only getDecoratedClass() declared -&gt; dispatch to proxy config.</span>
			<span class="token keyword">return</span> AopProxyUtils<span class="token punctuation">.</span><span class="token function">ultimateTargetClass</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>advised<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>advised<span class="token punctuation">.</span>opaque <span class="token operator">&amp;&amp;</span> method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isInterface</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
				method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isAssignableFrom</span><span class="token punctuation">(</span>Advised<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// Service invocations on ProxyConfig with the proxy config...</span>
			<span class="token keyword">return</span> AopUtils<span class="token punctuation">.</span><span class="token function">invokeJoinpointUsingReflection</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>advised<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		Object retVal<span class="token punctuation">;</span>

		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>advised<span class="token punctuation">.</span>exposeProxy<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// Make invocation available if necessary.</span>
			oldProxy <span class="token operator">=</span> AopContext<span class="token punctuation">.</span><span class="token function">setCurrentProxy</span><span class="token punctuation">(</span>proxy<span class="token punctuation">)</span><span class="token punctuation">;</span>
			setProxyContext <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		<span class="token comment">// Get as late as possible to minimize the time we "own" the target,</span>
		<span class="token comment">// in case it comes from a pool.</span>
		target <span class="token operator">=</span> targetSource<span class="token punctuation">.</span><span class="token function">getTarget</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		Class<span class="token operator">&lt;</span><span class="token operator">?</span><span class="token operator">&gt;</span> targetClass <span class="token operator">=</span> <span class="token punctuation">(</span>target <span class="token operator">!=</span> null <span class="token operator">?</span> target<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> null<span class="token punctuation">)</span><span class="token punctuation">;</span>

		<span class="token comment">// 2.获取当前bean被拦截方法链表</span>
		List<span class="token generics function"><span class="token punctuation">&lt;</span>Object<span class="token punctuation">&gt;</span></span> chain <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>advised<span class="token punctuation">.</span><span class="token function">getInterceptorsAndDynamicInterceptionAdvice</span><span class="token punctuation">(</span>method<span class="token punctuation">,</span> targetClass<span class="token punctuation">)</span><span class="token punctuation">;</span>

		<span class="token comment">// Check whether we have any advice. If we don't, we can fallback on direct</span>
		<span class="token comment">// reflective invocation of the target, and avoid creating a MethodInvocation.</span>
		<span class="token comment">// 3.如果为空,则直接调用target的method</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>chain<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// We can skip creating a MethodInvocation: just invoke the target directly</span>
			<span class="token comment">// Note that the final invoker must be an InvokerInterceptor so we know it does</span>
			<span class="token comment">// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.</span>
			Object<span class="token punctuation">[</span><span class="token punctuation">]</span> argsToUse <span class="token operator">=</span> AopProxyUtils<span class="token punctuation">.</span><span class="token function">adaptArgumentsIfNecessary</span><span class="token punctuation">(</span>method<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
			retVal <span class="token operator">=</span> AopUtils<span class="token punctuation">.</span><span class="token function">invokeJoinpointUsingReflection</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> method<span class="token punctuation">,</span> argsToUse<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token comment">// 4.不为空,则逐一调用chain中的每一个拦截方法的proceed</span>
		<span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// We need to create a method invocation...</span>
			MethodInvocation invocation <span class="token operator">=</span>
					<span class="token keyword">new</span> <span class="token class-name">ReflectiveMethodInvocation</span><span class="token punctuation">(</span>proxy<span class="token punctuation">,</span> target<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> targetClass<span class="token punctuation">,</span> chain<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token comment">// Proceed to the joinpoint through the interceptor chain.</span>
			retVal <span class="token operator">=</span> invocation<span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		<span class="token comment">// Massage return value if necessary.</span>
		Class<span class="token operator">&lt;</span><span class="token operator">?</span><span class="token operator">&gt;</span> returnType <span class="token operator">=</span> method<span class="token punctuation">.</span><span class="token function">getReturnType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>retVal <span class="token operator">!=</span> null <span class="token operator">&amp;&amp;</span> retVal <span class="token operator">==</span> target <span class="token operator">&amp;&amp;</span>
				returnType <span class="token operator">!=</span> Object<span class="token punctuation">.</span><span class="token keyword">class</span> <span class="token operator">&amp;&amp;</span> returnType<span class="token punctuation">.</span><span class="token function">isInstance</span><span class="token punctuation">(</span>proxy<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
				<span class="token operator">!</span>RawTargetAccess<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">isAssignableFrom</span><span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// Special case: it returned "this" and the return type of the method</span>
			<span class="token comment">// is type-compatible. Note that we can't help if the target sets</span>
			<span class="token comment">// a reference to itself in another returned object.</span>
			retVal <span class="token operator">=</span> proxy<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>retVal <span class="token operator">==</span> null <span class="token operator">&amp;&amp;</span> returnType <span class="token operator">!=</span> Void<span class="token punctuation">.</span>TYPE <span class="token operator">&amp;&amp;</span> returnType<span class="token punctuation">.</span><span class="token function">isPrimitive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">AopInvocationException</span><span class="token punctuation">(</span>
					<span class="token string">"Null return value from advice does not match primitive return type for: "</span> <span class="token operator">+</span> method<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">return</span> retVal<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">finally</span> <span class="token punctuation">{<!-- --></span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>target <span class="token operator">!=</span> null <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>targetSource<span class="token punctuation">.</span><span class="token function">isStatic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// Must have come from TargetSource.</span>
			targetSource<span class="token punctuation">.</span><span class="token function">releaseTarget</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>setProxyContext<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// Restore old proxy.</span>
			AopContext<span class="token punctuation">.</span><span class="token function">setCurrentProxy</span><span class="token punctuation">(</span>oldProxy<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

	@Override
	@Nullable
	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
	Object interceptorOrInterceptionAdvice <span class="token operator">=</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>interceptorsAndDynamicMethodMatchers<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token operator">++</span><span class="token keyword">this</span><span class="token punctuation">.</span>currentInterceptorIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>interceptorOrInterceptionAdvice <span class="token keyword">instanceof</span> <span class="token class-name">InterceptorAndDynamicMethodMatcher</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token comment">// Evaluate dynamic method matcher here: static part will already have</span>
		<span class="token comment">// been evaluated and found to match.</span>
		InterceptorAndDynamicMethodMatcher dm <span class="token operator">=</span>
				<span class="token punctuation">(</span>InterceptorAndDynamicMethodMatcher<span class="token punctuation">)</span> interceptorOrInterceptionAdvice<span class="token punctuation">;</span>
		Class<span class="token operator">&lt;</span><span class="token operator">?</span><span class="token operator">&gt;</span> targetClass <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>targetClass <span class="token operator">!=</span> null <span class="token operator">?</span> <span class="token keyword">this</span><span class="token punctuation">.</span>targetClass <span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>dm<span class="token punctuation">.</span>methodMatcher<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">,</span> targetClass<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>arguments<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			<span class="token keyword">return</span> dm<span class="token punctuation">.</span>interceptor<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
			<span class="token comment">// Dynamic matching failed.</span>
			<span class="token comment">// Skip this interceptor and invoke the next in the chain.</span>
			<span class="token keyword">return</span> <span class="token function">proceed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
		<span class="token comment">// It's an interceptor, so we just invoke it: The pointcut will have</span>
		<span class="token comment">// been evaluated statically before this object was constructed.</span>
		<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>MethodInterceptor<span class="token punctuation">)</span> interceptorOrInterceptionAdvice<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

依次遍历拦截器链的每个元素,然后调用其实现,将真正调用工作委托给各个增强器



总结

所以当我们开启了Aop的注解以后,就会执行以下步骤

  1. AspectJAutoProxyBeanDefinitionParser 注册 AnnotationAwareAspectJAutoProxyCreator
  2. 再执行bean后置处理器的after方法回调时,判断该bean是否有advice
  3. 如果有则把bean包装为proxy对象返回
  4. 以后调用bean的方法时,通过proxy来调用,proxy依次调用增强器的相关方法,实现方法的切入