在上一篇 重拾-Spring AOP
中咱們會發現 Spring AOP 是經過類 ProxyFactoryBean
建立代理對象,其有個缺陷就是隻能代理一個目標對象 bean, 當代理目標類過多時,配置文件臃腫不方便管理維護,所以 Spring 提供了可以實現自動建立代理的類 BeanNameAutoProxyCreator
, DefaultAdvisorAutoProxyCreator
;下面咱們看下兩者是如何實現自動代理的。java
BeanNameAutoProxyCreator
是經過判斷當前 bean name 是否匹配,只有匹配的 bean 纔會建立代理。
<bean id="userService" class="org.springframework.aop.UserServiceImpl" /> <bean id="demoService" class="org.springframework.aop.DemoServiceImpl" /> <bean id="userBeforeAdvice" class="org.springframework.aop.UserBeforeAdvice" /> <bean id="userAfterAdvice" class="org.springframework.aop.UserAfterAdvice" /> <bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!-- 配置要代理的 bean --> <property name="beanNames"> <list> <value>userService</value> <value>demoService</value> </list> </property> <!-- 配置 interceptor, advice, advisor --> <property name="interceptorNames"> <list> <value>userAfterAdvice</value> <value>userBeforeAdvice</value> </list> </property> </bean>
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml"); UserService userService = (UserService) ctx.getBean("userService"); userService.say(); DemoService demoService = (DemoService) ctx.getBean("demoService"); demoService.demo();
do before advice .... do say method do after return advice .... do before advice .... do demo. do after return advice ....
如上圖 BeanNameAutoProxyCreator
類結構能夠看出,其實現了接口 BeanPostProcessor
; 那麼咱們能夠大概猜想出其自動代理的實現原理與自動注入相似,都是在 bean 實例化後進行特殊的處理,下面就讓咱們看下源碼驗證下吧。正則表達式
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException { // Check for special cases. We don't want to try to autoproxy a part of the autoproxying // infrastructure, lest we get a stack overflow. if (isInfrastructureClass(bean, name) || shouldSkip(bean, name)) { logger.debug("Did not attempt to autoproxy infrastructure class '" + bean.getClass() + "'"); return bean; } TargetSource targetSource = getTargetSource(bean, name); Object[] specificInterceptors = getInterceptorsAndAdvisorsForBean(bean, name); // proxy if we have advice or if a TargetSourceCreator wants to do some // fancy stuff such as pooling if (specificInterceptors != DO_NOT_PROXY || !(targetSource instanceof SingletonTargetSource)) { // handle prototypes correctly // 獲取容器中配置的 advisors Advisor[] commonInterceptors = resolveInterceptorNames(); List allInterceptors = new ArrayList(); if (specificInterceptors != null) { allInterceptors.addAll(Arrays.asList(specificInterceptors)); if (commonInterceptors != null) { if (this.applyCommonInterceptorsFirst) { allInterceptors.addAll(0, Arrays.asList(commonInterceptors)); } else { allInterceptors.addAll(Arrays.asList(commonInterceptors)); } } } if (logger.isInfoEnabled()) { int nrOfCommonInterceptors = commonInterceptors != null ? commonInterceptors.length : 0; int nrOfSpecificInterceptors = specificInterceptors != null ? specificInterceptors.length : 0; logger.info("Creating implicit proxy for bean '" + name + "' with " + nrOfCommonInterceptors + " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors"); } ProxyFactory proxyFactory = new ProxyFactory(); // copy our properties (proxyTargetClass) inherited from ProxyConfig proxyFactory.copyFrom(this); if (!getProxyTargetClass()) { // Must allow for introductions; can't just set interfaces to // the target's interfaces only. // 添加設置代理的接口 Class[] targetsInterfaces = AopUtils.getAllInterfaces(bean); for (int i = 0; i < targetsInterfaces.length; i++) { proxyFactory.addInterface(targetsInterfaces[i]); } } for (Iterator it = allInterceptors.iterator(); it.hasNext();) { Advisor advisor = GlobalAdvisorAdapterRegistry.getInstance().wrap(it.next()); // 添加 advisor proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(getTargetSource(bean, name)); // 建立代理對象,依舊採用的 jdk 動態代理; 由於上面設置了代理的 interface return proxyFactory.getProxy(); } else { return bean; } }
protected Object[] getInterceptorsAndAdvisorsForBean(Object bean, String beanName) { if (this.beanNames != null) { // bean name 包含在配置的名稱列表中,說明須要代理 if (this.beanNames.contains(beanName)) { return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; } for (Iterator it = this.beanNames.iterator(); it.hasNext();) { String mappedName = (String) it.next(); // bean name 匹配通配符,說明須要代理 if (isMatch(beanName, mappedName)) { return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; } } } // 說明 bean 不須要代理 return DO_NOT_PROXY; }
protected boolean isMatch(String beanName, String mappedName) { // bean name 匹配通配符 return (mappedName.endsWith("*") && beanName.startsWith(mappedName.substring(0, mappedName.length() - 1))) || (mappedName.startsWith("*") && beanName.endsWith(mappedName.substring(1, mappedName.length()))); }
從 BeanNameAutoProxyCreator
的源碼大概總結其自動代理流程:spring
DefaultAdvisorAutoProxyCreator
會搜索BeanFactory
容器內部全部可用的Advisor
; 併爲容器中匹配的 bean 建立代理。 在上一篇重拾-Spring AOP
中咱們知道 Spring AOP 會默認建立實例爲DefaultPointcutAdvisor
的Advisor
; 那麼在分析DefaultAdvisorAutoProxyCreator
以前,咱們看下 Spring AOP 還爲咱們提供了哪些內置的Advisor
。
NameMatchMethodPointcutAdvisor
是按 method name 匹配,只有當目標類執行方法匹配的時候,纔會執行Advice
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut { // 配置攔截的 method name private String[] mappedNames = new String[0]; public boolean matches(Method m, Class targetClass) { for (int i = 0; i<this.mappedNames.length; i++) { String mappedName = this.mappedNames[i]; // 目標方法是否與配置的 method name 相等;或者匹配通配符 if (mappedName.equals(m.getName()) || isMatch(m.getName(), mappedName)) { return true; } } return false; } // 是否以 * 開頭或結束並匹配 protected boolean isMatch(String methodName, String mappedName) { return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1))) || (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length()))); } }
RegexpMethodPointcutAdvisor
是按照正則表達式匹配方法,可以精肯定位到須要攔截的方法。
public class RegexpMethodPointcut extends StaticMethodMatcherPointcut implements ClassFilter { public boolean matches(Method m, Class targetClass) { // TODO use target class here? // 拼接表達式 String patt = m.getDeclaringClass().getName() + "." + m.getName(); for (int i = 0; i < this.compiledPatterns.length; i++) { // 正則匹配 boolean matched = this.matcher.matches(patt, this.compiledPatterns[i]); if (logger.isDebugEnabled()) { logger.debug("Candidate is: '" + patt + "'; pattern is " + this.compiledPatterns[i].getPattern() + "; matched=" + matched); } if (matched) { return true; } } return false; } public boolean matches(Class clazz) { // TODO do with regexp return true; } public ClassFilter getClassFilter() { return this; } }
<beans> <bean id="userService" class="org.springframework.aop.UserServiceImpl" /> <bean id="demoService" class="org.springframework.aop.DemoServiceImpl" /> <bean id="userBeforeAdvice" class="org.springframework.aop.UserBeforeAdvice" /> <bean id="userAfterAdvice" class="org.springframework.aop.UserAfterAdvice" /> <!-- 按方法名稱匹配 --> <bean id="nameMatchMethodPointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="mappedNames"> <!-- 匹配 save 開頭的方法 --> <value>save*</value> </property> <property name="advice"> <ref bean="userBeforeAdvice" /> </property> </bean> <bean id="regexpMethodPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="pattern"> <!-- 匹配以 del 開頭的方法 --> <value>org.springframework.aop.*.del*.*</value> </property> <property name="advice"> <ref bean="userAfterAdvice" /> </property> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" /> </beans>
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml"); UserService userService = (UserService) ctx.getBean("userService"); userService.saveUser(); userService.delUser(); DemoService demoService = (DemoService) ctx.getBean("demoService"); demoService.saveDemo(); demoService.delDemo();
do before advice .... do save user ...... do del user ...... do after return advice .... do before advice .... do save demo ...... do del demo ...... do after return advice ....
從測試結果能夠看出,經過配置不一樣Advisor
匹配不一樣的Method
採用相應的Advice
進行處理。
從上圖 DefaultAdvisorAutoProxyCreator
類結構,咱們知道其實現與 BeanNameAutoProxyCreator
相似;都是經過實現接口 BeanPostProcessor
在 bean 完成實例化後進行自動代理處理。app
因 DefaultAdvisorAutoProxyCreator
和 BeanNameAutoProxyCreator
都繼承了類 AbstractAutoProxyCreator
,因此從源碼中咱們能夠發現兩者都重寫了方法 getInterceptorsAndAdvisorsForBean
,也就是在獲取當前 bean 所匹配的 Advisor
邏輯不同以外其餘處理一致; 那麼下面針對 DefaultAdvisorAutoProxyCreator
的實現咱們主要看下方法 getInterceptorsAndAdvisorsForBean
的處理。源碼分析
protected Object[] getInterceptorsAndAdvisorsForBean(Object bean, String name) { // 查找與當前 bean 匹配的 advisor List advices = findEligibleAdvisors(bean.getClass()); if (advices.isEmpty()) { return DO_NOT_PROXY; } // 對 advisor 集合排序 advices = sortAdvisors(advices); return advices.toArray(); }
protected List findEligibleAdvisors(Class clazz) { // 查找當前容器中全部定義的 advisor List candidateAdvice = findCandidateAdvisors(); List eligibleAdvice = new LinkedList(); for (int i = 0; i < candidateAdvice.size(); i++) { // Sun, give me generics, please! Advisor candidate = (Advisor) candidateAdvice.get(i); // 判斷 bean 是否能夠應用 advisor if (AopUtils.canApply(candidate, clazz, null)) { // 將 advisor 添加到匹配的集合中 eligibleAdvice.add(candidate); logger.info("Candidate Advice [" + candidate + "] accepted for class [" + clazz.getName() + "]"); } else { logger.info("Candidate Advice [" + candidate + "] rejected for class [" + clazz.getName() + "]"); } } return eligibleAdvice; }
protected List findCandidateAdvisors() { if (!(getBeanFactory() instanceof ListableBeanFactory)) { throw new IllegalStateException("Cannot use DefaultAdvisorAutoProxyCreator without a ListableBeanFactory"); } ListableBeanFactory owningFactory = (ListableBeanFactory) getBeanFactory(); // 從容器中查找全部 bean 定義 type 爲 Advisor 的 bean name String[] adviceNames = BeanFactoryUtils.beanNamesIncludingAncestors(owningFactory, Advisor.class); List candidateAdvisors = new LinkedList(); for (int i = 0; i < adviceNames.length; i++) { String name = adviceNames[i]; if (!this.usePrefix || name.startsWith(this.advisorBeanNamePrefix)) { // 獲取 advisor 實例 Advisor advisor = (Advisor) owningFactory.getBean(name); candidateAdvisors.add(advisor); } } return candidateAdvisors; }
public static boolean canApply(Advisor advisor, Class targetClass, Class[] proxyInterfaces) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; // 經過 advisor 的 pointcut 判斷 bean 是否匹配 return canApply(pca.getPointcut(), targetClass, proxyInterfaces); } else { // It doesn't have a pointcut so we assume it applies return true; } } public static boolean canApply(Pointcut pc, Class targetClass, Class[] proxyInterfaces) { // 類是否匹配 if (!pc.getClassFilter().matches(targetClass)) { return false; } // 判斷類中的 method 是否匹配 // 獲取類下全部的method Method[] methods = targetClass.getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; // If we're looking only at interfaces and this method // isn't on any of them, skip it if (proxyInterfaces != null && !methodIsOnOneOfTheseInterfaces(m, proxyInterfaces)) { continue; } // 執行 pointcut 的 method match if (pc.getMethodMatcher().matches(m, targetClass)) return true; } return false; }
從 DefaultAdvisorAutoProxyCreator
的源碼分析,可知其自動代理流程大概以下:post
Advisor
實例Advisor
從 BeanNameAutoProxyCreator
, DefaultAdvisorAutoProxyCreator
兩者的實現能夠看出其相同點測試
BeanPostProcessor
的實現Advisor
,後在建立代理對象兩者的不一樣點在於:this
Advisor
內部的 Ponitcut
匹配判斷Advisor
是用戶配置的,後者是容器中全部匹配的 Advisor