簡析Spring aop的BeanNameAutoProxyCreator如何對目標類生成代理

    注意:咱們分析的版本是SpringFramework-3.2.8.RELEASE。java

    先上一張圖,以下圖1所示,後面會用到:spring

                                 圖1 BeanNameAutoProxyCreator間接繼承了BeanPostProcessorapp

1.鋪墊

類Seller、Waiter、GreetingBeforeAdvice的代碼以下,先作下鋪墊:ide

public class Seller {

    public void greetTo(String name) {
        LOG.info("Seller greet to: {}", name);
    }
    
}
public class Waiter {

    public void greetTo(String name){
        LOG.info("waiter greet to: {}",name);
    }

    public void serveTo(String name){
        LOG.info("waiter serving to: {}",name);
    }
    
}
import org.springframework.aop.MethodBeforeAdvice;

import com.mjduan.project.log.LOG;

/**
 * @author mjduan@yahoo.com 2018-05-03 13:20
 * @version 0.0.1
 * @since 0.0.1
 */
public class GreetingBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        LOG.info("Greeting before advice: {}", args[0]);
    }
}

spring的xml配置以下:post

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <context:component-scan base-package="com.mjduan.project"/>

    <bean id="seller" class="com.mjduan.project.example4.Seller"/>
    <bean id="waiter" class="com.mjduan.project.example4.Waiter"/>
    <bean id="greetingAdvice" class="com.mjduan.project.example4.GreetingBeforeAdvice"/>

    <bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*er"/>
        <property name="interceptorNames" value="greetingAdvice"/>
        <property name="optimize" value="true"/>
    </bean>
</beans>

 單元測試代碼以下:單元測試

@Test
public void test1(){
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring4.xml");
    Waiter waiter = applicationContext.getBean("waiter", Waiter.class);
    Seller seller = applicationContext.getBean("seller", Seller.class);

    waiter.greetTo("John");
    seller.greetTo("Tom");
}

    到這裏,鋪墊基本是完成了,下面開始分析。測試

    上面的單元測試代碼中waiter、seller實際上是Cglib生成的代理對象,這個能夠本身打斷點查看。this

2.代理類是如何生成的

    1.BeanPostProcessor的postProcessAfterInitialization做用

    先說明下BeanPostProcessor的postProcessAfterInitialization(...)的做用,由於這個是後面內容的鋪墊。假設Spring容器中beanNameX對應的bean是A,那麼通過某個類(這個類實現了BeanPostProcessor接口)的postProcessAfterInitialization(A,beanNameX)處理後返回B,則此時Spring容器中beanNameX對應的bean是B,而不是A。spa

    在AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsAfterInitialization中,會調用BeanPostProcessor的postProcessAfterInitialization。代理

    2.Waiter代理類的是如何生成的

    AbstractAutowireCapableBeanFactory調用BeanNameAutoProxyCreator的圖以下圖2所示,有些步驟被我省略了,主要集中與主流程,由於分支太多了,難以所有遍佈。

                         圖2 AbstractAutowireCapableBeanFactory調用BeanNameAutoProxyCreator

   applicationContext.getBean("waiter", Waiter.class)時,會調用BeanNameAutoProxyCreator的postProcessAfterInitialization,如圖2的步驟1,這個方法返回的對象就是用Cglib生成的代理對象waiter,因此咱們從Spring中拿到的是代理類,而不是waiter對象。以下所示,wrapIfNecessary方法裏面的就是咱們重點分析的內容。

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.containsKey(cacheKey)) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

     步驟3中的getAdvicesAndAdvisorsForBean方法,就是判斷是否須要被代理的邏輯代碼,這裏再也不分析。

     步驟4中,經過ProxyFactory的getProxy(),來生成代理類。

 

從Spring容器中拿到的Seller,是由Cglib生成的代理對象,同上述的Waiter。

3.思考

    3.1.思考1    

  GreetingBeforeAdvice在waiter.greetTo()和seller.greetTo()的前調用是如何實現的?這個與ProxyFactory的advisor有關,圖2的步驟4中有涉及。

    3.2.思考2

    咱們在spring xml配置文件中定義了BeanNameAutoProxyCreator,並未對其設置什麼,Spring是如何調用它的方法postProcessAfterInitialization? 來看下AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsAfterInitialization實現,以下所示:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean;
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		result = beanProcessor.postProcessAfterInitialization(result, beanName);
		if (result == null) {
			return result;
		}
	}
	return result;
}

    首先從容器中取出全部的BeanPostProcessor,逐個對其調用postProcessAfterInitialization,而咱們的BeanNameAutoProxyCreator剛好是BeanPostProcessor,因此在這裏BeanNameAutoProxyCreator的postProcessAfterInitialization就會被調用到。

 

4.Reference

  • SpringFramework-3.2.8.RELEASE.
  • 精通Spring4.x企業應用開發實踐,我的不是很喜歡用精通二字,但此書確實相比其它,寫的稍微好多了。
相關文章
相關標籤/搜索