Spring AOP 源碼解析系列,建議你們按順序閱讀,歡迎討論spring
上一章中咱們分析了ProxyFactory,它是Spring AOP核心的底層實現。然而硬編碼的方式仍是過於繁瑣且不易使用,本章咱們將討論ProxyFactoryBean,它結合了ProxyFactory和Ioc中的FactoryBean擴展,使得能夠經過XML配置的方式來實現Spring AOP。關於Spring AOP建立代理的具體實現本章將不會再贅述,而是主要討論FactoryBean擴展結合Spring AOP的使用。chrome
我在IOC容器(四)-FactoryBean一篇中已詳細地介紹了FactoryBean在Spring IOC中的實現原理,這裏仍是簡單介紹一下。緩存
FactoryBean顧名思義,工廠Bean,便可以動態建立Bean的Bean。對於一些只有在運行時才能明確的對象來講,直接在XML中定義已不能知足,而是經過定義一個工廠類,在運行時根據不一樣配置來生成最終的對象。框架
FactoryBean是Spring IOC的兩大擴展之一(另外一個是BeanPostProcessor),由此與Spring集成的功能衆多,包括但不限於AOP,ORM,事務管理,Remoting。ide
簡單看下AbstractBeanFactory中對FactoryBean處理的代碼this
// 單例 if (mbd.isSingleton()) { // 獲取單例的bean對象 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { [@Override](https://my.oschina.net/u/1162528) public Object getObject() throws BeansException { try { // 匿名內部類中建立bean對象 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); // 處理FactoryBean擴展 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
能夠看到,對象建立完成後會判斷是否爲FactoryBean的子類,若是是,則會調用getObject方法返回真正的對象。編碼
回到ProxyFactoryBean,先貼出以前例子的配置。.net
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 原始對象 --> <bean id="chromeBrowser" class="com.lcifn.spring.aop.bean.ChromeBrowser"/> <!-- 環繞加強對象 --> <bean id="browserAroundAdvice" class="com.lcifn.spring.aop.advice.BrowserAroundAdvice"></bean> <bean id="browserProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 接口 --> <property name="interfaces" value="com.lcifn.spring.aop.bean.Browser"/> <!-- 要代理的對象 --> <property name="target" ref="chromeBrowser"/> <!-- 攔截器組 --> <property name="interceptorNames"> <list> <value>browserAroundAdvice</value> </list> </property> </bean> </beans>
基本配置就不說了,按照上面FactoryBean的介紹,Spring建立完ProxyFactoryBean對象後,就會調用其getObject方法。prototype
public Object getObject() throws BeansException { // 初始化Advisor鏈 initializeAdvisorChain(); // 獲取真正的代理對象 if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } }
getObject方法就作了兩件事,一是初始化Advisor鏈,二是建立代理對象,不過建立代理對象時區分單例和多例。設計
簡單地說,就是將配置中的interceptorNames轉化成Advisor對象。其中又分爲名稱精確匹配和名稱全局匹配兩種,精確匹配就不用說了,全局匹配就是以*號結尾的這種。
對於全局匹配這種,就是在BeanFactory中匹配全部Advisor和Interceptor類型的Bean,再用*前的名稱前綴去匹配Bean的名稱。
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) { String[] globalAdvisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class); String[] globalInterceptorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class); List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length); Map<Object, String> names = new HashMap<Object, String>(beans.size()); for (String name : globalAdvisorNames) { Object bean = beanFactory.getBean(name); beans.add(bean); names.put(bean, name); } for (String name : globalInterceptorNames) { Object bean = beanFactory.getBean(name); beans.add(bean); names.put(bean, name); } OrderComparator.sort(beans); for (Object bean : beans) { String name = names.get(bean); if (name.startsWith(prefix)) { addAdvisorOnChainCreation(bean, name); } } }
而對於精確匹配的更加清晰,直接取BeanFactory中找,而若是ProxyFactoryBean的singleton屬性設置爲false時,則封裝爲PrototypePlaceholderAdvisor延遲建立。
// 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);
兩種方式最後都經過addAdvisorOnChainCreation來執行添加操做。其中重要的是將根據name從BeanFactory中得到的對象轉換成Advisor,由於interceptorNames支持Advisor,Advice,MethodInterceptor多種類型的對象name,經過namedBeanToAdvisor方法統一轉成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. // 轉換Bean對象爲Advisor Advisor advisor = namedBeanToAdvisor(next); if (logger.isTraceEnabled()) { logger.trace("Adding advisor with name '" + name + "'"); } addAdvisor(advisor); } private Advisor namedBeanToAdvisor(Object next) { try { return this.advisorAdapterRegistry.wrap(next); } catch (UnknownAdviceTypeException ex) { // We expected this to be an Advisor or Advice, // but it wasn't. This is a configuration error. 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); } }
這裏的advisorAdapterRegistry實現爲DefaultAdvisorAdapterRegistry,這個wrap方法也是被多個地方調用以達到統一Advisor,以後方便生成代理攔截器鏈。
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); }
建立代理對象時根據singleton屬性決定建立的對象是單例仍是多例。咱們以單例的來看
private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { // 返回targetSource this.targetSource = freshTargetSource(); // 自動發現目標對象的接口集合 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"); } setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // Initialize the shared singleton instance. super.setFrozen(this.freezeProxy); // 獲取代理對象 this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; }
freshTargetSource判斷targetName爲null,直接返回targetSource,不然從beanFactory根據targetName獲取target對象。
對於代理接口集合爲空,且proxyTargetClass爲空時,從targetClass獲取其實現的接口集合做爲代理接口。於是在配置ProxyFactoryBean時,能夠不用指定interfaces屬性。
getProxy方法的實現同ProxyFactory一致,都是經過AopProxyFactory->AopProxy->Proxy的方式,具體可見ProxyFactory中的建立代理一節。返回的對象賦予類變量做爲單例緩存。
對於多例的狀況,調用的newPrototypeInstance方法
private synchronized Object newPrototypeInstance() { ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory()); // The copy needs a fresh advisor chain, and a fresh TargetSource. TargetSource targetSource = freshTargetSource(); copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain()); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. copy.setInterfaces( ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader)); } copy.setFrozen(this.freezeProxy); if (logger.isTraceEnabled()) { logger.trace("Using ProxyCreatorSupport copy: " + copy); } return getProxy(copy.createAopProxy()); }
經過建立一個新的基類對象ProxyCreatorSupport,並copy全部配置的方式每次生成一個新的對象,最後經過getProxy方法獲取代理對象。
至此ProxyFactoryBean的介紹就結束了,它主要的特色就是使用FactoryBean同IOC進行告終合。你們都知道Spring框架是一種微內核的設計,包括其AOP,事務管理等許多功能都是經過擴展的方式來設計的。而這種設計思想隨着深刻到各功能源碼,包括一些其餘框架同Spring的整合,不能不說這是Spring生態繁榮的一個重要緣由。