Spring-aop-ProxyFactoryBeanソースコード分析


本編を読む前に、まず読んでください.
http://wangxinchun.iteye.com/blog/2079024,繰り返しのロジック,本編では解析を行わない~
スプリングフレームワークには鮮明な特徴があり、一般的なサービスにはプログラミング式と構成式の2つの実現があります.
プログラミング方式の使用は往々にして明らかであるが、機能は相対的に弱く、使用は簡潔ではない.構成式は往々にしてspringのiocフレームワークと結合することができ、より緩やかでより強力な機能を提供し、springフレームワークがすべての面で表現されていることを兼ね備えている.
ProxyFactoryがAOPブロッキングを実現する方式に対してProxyFactoryBean  構成によってすべてのブロック機能を実現します.
使用case:
ビジネスクラス

public interface LoginService {
	public boolean login(User user);
}
public class LoginServiceImpl implements LoginService {
	public boolean login(User user) {
		System.out.println(user);
		if (user == null) {
			return false;
		} else if (user.getUsername() == "xinchun.wang" && user.getPassword() == "123456") {
			return true;
		}
		return false;
	}
}

拡張(Advice,Interceptor)

public class AfterAdvice1 implements AfterReturningAdvice{
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("AfterAdvice1.afterReturning() execute ");
	}
}
public class AfterAdvice2 implements AfterReturningAdvice{
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("AfterAdvice2.afterReturning() execute ");
	}
}

public class BeforeAdvice1 implements MethodBeforeAdvice{
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("BeforeAdvice1.before() execute ");
	}
}
public class BeforeAdvice2 implements MethodBeforeAdvice{
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("BeforeAdvice2.before() execute ");
	}
}

その他の補助ツールコード:

public class BeanFactoryUtils implements BeanFactoryAware{
	private static BeanFactory beanFactory;
	public static BeanFactoryUtils getInstance(){
		return (BeanFactoryUtils)beanFactory.getBean("factoryUtil");
	}
	public void setBeanFactory(BeanFactory bf) throws BeansException {
        beanFactory = bf;		
	}
	public BeanFactory getBeanFactory() {
		return beanFactory;
	}
}

アプリケーションContext.xml構成

<bean id="afterAdvice1" class="com.qunar.service.AfterAdvice1" />
	<bean id="afterAdvice2" class="com.qunar.service.AfterAdvice2" />
	<bean id="beforeAdvice1" class="com.qunar.service.BeforeAdvice1" />
	<bean id="beforeAdvice2" class="com.qunar.service.BeforeAdvice1" />
<bean id="loginService" class="com.qunar.service.LoginServiceImpl"/>
	<bean id="factoryUtil" class=" com.qunar.util.BeanFactoryUtils" />
	<bean id="loginServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!--         -->
		<property name="proxyInterfaces">
			<value> com.qunar.service.LoginService</value>
		</property>
		<!-- ProxyFactoryBean        -->
		<property name="target">
			<ref bean="loginService" />
		</property>
		<!--    Advice -->
		<property name="interceptorNames">
			<list>
				<value>afterAdvice1</value>
				<value>afterAdvice2</value>
				<value>beforeAdvice1</value>
				<value>beforeAdvice2</value>
			</list>
		</property>
	</bean>

テスト:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:META-INF/spring/applicationContext.xml"})
public class LoginServiceImplTest {
	@Test
	public void proxyLoginTest() {
		LoginService loginService = (LoginService)BeanFactoryUtils.getInstance().getBeanFactory().getBean("loginServiceProxy");
		loginService.login(new User("xinchun.wang","123456"));
	}
}

出力:
BeforeAdvice1.before() execute
BeforeAdvice1.before() execute
com.qunar.vo.User@111b910
AfterAdvice2.afterReturning() execute
AfterAdvice1.afterReturning() execute
概要:
ProxyFactoryBeanは継承システムにおいてProxyFactoryとあまり差はありませんが、ProxyFactoryBeanはBeanFactoryAware BeanClassLoaderAware FactoryBeanの3つのインターフェースを実現しています.IOCコンテナに詳しいとProxyFactoryBeanとIOCコンテナが融合していることがわかります.ProxyFactoryBeanはIOCコンテナの配置を借りているのですが、Advice拡張オブジェクトとtargetオブジェクトを見つけます.
次にソースプロファイルに入ります

public class ProxyFactoryBean extends ProxyCreatorSupport
		implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {

	/**
	 * interceptor       
	 */
	public static final String GLOBAL_SUFFIX = "*";

	protected final Log logger = LogFactory.getLog(getClass());
  //      
	private String[] interceptorNames;
	//       
	private String targetName;

	private boolean autodetectInterfaces = true;

	private boolean singleton = true;
	//    ProxyFactory      ,     。         。
	private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();

	private boolean freezeProxy = false;

	private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();

	private transient boolean classLoaderConfigured = false;
  //IOC  
	private transient BeanFactory beanFactory;

	/** Whether the advisor chain has already been initialized */
	private boolean advisorChainInitialized = false;

	/**     ,singletonInstance       */
	private Object singletonInstance;


	/**
	 *        ,      ,    cglib2   。
	 */
	public void setProxyInterfaces(Class[] proxyInterfaces) throws ClassNotFoundException {
		setInterfaces(proxyInterfaces);
	}

	/**
	    interceptorNames       ,         IOC      。
	  interceptorNames             Interceptor, Advisor or Advice,
	         IOC        ,     Advice     Advisor,   
	  SingletonTargetSource         ,   target    targetSource   targetName
	     ,   interceptorNames      Advice/Advisor bean names.*/
	
	public void setInterceptorNames(String[] interceptorNames) {
		this.interceptorNames = interceptorNames;
	}

	/**
	 *   targetname
	 */
	public void setTargetName(String targetName) {
		this.targetName = targetName;
	}

	/**
	 *           ,   true,   false,         cglib   。
	 */
	public void setAutodetectInterfaces(boolean autodetectInterfaces) {
		this.autodetectInterfaces = autodetectInterfaces;
	}

	/**
	 *         
	 */
	public void setSingleton(boolean singleton) {
		this.singleton = singleton;
	}

	/**
	 *you know。。。
	 */
	public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
		this.advisorAdapterRegistry = advisorAdapterRegistry;
	}

	@Override
	public void setFrozen(boolean frozen) {
		this.freezeProxy = frozen;
	}

	
	public void setProxyClassLoader(ClassLoader classLoader) {
		this.proxyClassLoader = classLoader;
		this.classLoaderConfigured = (classLoader != null);
	}

	public void setBeanClassLoader(ClassLoader classLoader) {
		if (!this.classLoaderConfigured) {
			this.proxyClassLoader = classLoader;
		}
	}
  //   beanfacotry    。
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
		checkInterceptorNames();
	}


	/**
	 *        ,      !!!
	 */
	public Object getObject() throws BeansException {
		initializeAdvisorChain(); //            advice        Advisor
		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(); //     
		}
	}


	public Class<?> getObjectType() {
		synchronized (this) {
			if (this.singletonInstance != null) {
				return this.singletonInstance.getClass();
			}
		}
		Class[] ifcs = getProxiedInterfaces();
		if (ifcs.length == 1) {
			return ifcs[0];
		}
		else if (ifcs.length > 1) {
			return createCompositeInterface(ifcs);
		}
		else if (this.targetName != null && this.beanFactory != null) {
			return this.beanFactory.getType(this.targetName);
		}
		else {
			return getTargetClass();
		}
	}

	public boolean isSingleton() {
		return this.singleton;
	}


	/**
	 *         ,        ,         
	 */
	protected Class createCompositeInterface(Class[] interfaces) {
		return ClassUtils.createCompositeInterface(interfaces, this.proxyClassLoader);
	}

	/**
	 *          
	 */
	private synchronized Object getSingletonInstance() {
		if (this.singletonInstance == null) { //       
			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()); //     createAopProxy     AopProxyFactory         aop  (       ProxyFactory   )
		}
		return this.singletonInstance;
	}

	  //          
	private synchronized Object newPrototypeInstance() {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
		}
  
    // copy     ProxyFacotryBean    getAopProxyFactory            ,     
		ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
		// The copy needs a fresh advisor chain, and a fresh TargetSource.
		TargetSource targetSource = freshTargetSource();
		copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain()); // copy
		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());
	}

	/**
	 *          AopProxy  jdk  cglib    
	 */
	protected Object getProxy(AopProxy aopProxy) {
		return aopProxy.getProxy(this.proxyClassLoader);
	}

	/**
	 *     interceptorNames           advice   advisor ,     target
	 */
	private void checkInterceptorNames() {
		if (!ObjectUtils.isEmpty(this.interceptorNames)) {
			String finalName = this.interceptorNames[this.interceptorNames.length - 1];
			if (this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
				//            tareget  
				if (!finalName.endsWith(GLOBAL_SUFFIX) && !isNamedBeanAnAdvisorOrAdvice(finalName)) {
					// finalName      
					this.targetName = finalName;
					if (logger.isDebugEnabled()) {
						logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " +
								"is not an advisor class: treating it as a target or TargetSource");
					}
					String[] newNames = new String[this.interceptorNames.length - 1];
					System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length);
					this.interceptorNames = newNames;
				}
			}
		}
	}

	/**
	 *      Advisor   Advice
	 */
	private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) {
		Class namedBeanClass = this.beanFactory.getType(beanName);
		if (namedBeanClass != null) {
			return (Advisor.class.isAssignableFrom(namedBeanClass) || Advice.class.isAssignableFrom(namedBeanClass));
		}
		// Treat it as an target bean if we can't tell.
		if (logger.isDebugEnabled()) {
			logger.debug("Could not determine type of bean with name '" + beanName +
					"' - assuming it is neither an Advisor nor an Advice");
		}
		return false;
	}

	
	private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
		if (this.advisorChainInitialized) {
			return;
		}

		if (!ObjectUtils.isEmpty(this.interceptorNames)) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
						"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
			}

			//           ,        targetSource   targetName
			if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
					this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
				throw new AopConfigException("Target required after globals");
			}

			for (String name : this.interceptorNames) {
				if (logger.isTraceEnabled()) {
					logger.trace("Configuring advisor or advice '" + name + "'");
				}

				if (name.endsWith(GLOBAL_SUFFIX)) { //      *
					if (!(this.beanFactory instanceof ListableBeanFactory)) {
						throw new AopConfigException(
								"Can only use global advisors or interceptors with a ListableBeanFactory");
					}
					addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
							name.substring(0, name.length() - GLOBAL_SUFFIX.length())); //     advisor
				}

				else {
					// 
					Object advice;
					if (this.singleton || this.beanFactory.isSingleton(name)) {
						//      ,     Advisor/Advice to the chain.
						advice = this.beanFactory.getBean(name); 
					}
					else {
						//       advisor
						advice = new PrototypePlaceholderAdvisor(name);
					}
					addAdvisorOnChainCreation(advice, name);
				}
			}
		}

		this.advisorChainInitialized = true;
	}


	/**
	 *       advisor   ,    prototype      ,  
	 */
	private List<Advisor> freshAdvisorChain() {
		Advisor[] advisors = getAdvisors();
		List<Advisor> freshAdvisors = new ArrayList<Advisor>(advisors.length);
		for (Advisor advisor : advisors) {
			if (advisor instanceof PrototypePlaceholderAdvisor) { //     advisor  
				PrototypePlaceholderAdvisor pa = (PrototypePlaceholderAdvisor) advisor;
				if (logger.isDebugEnabled()) {
					logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");
				}
				if (this.beanFactory == null) {
					throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
							"- cannot resolve prototype advisor '" + pa.getBeanName() + "'");
				}
				Object bean = this.beanFactory.getBean(pa.getBeanName());
				Advisor refreshedAdvisor = namedBeanToAdvisor(bean);
				freshAdvisors.add(refreshedAdvisor);
			}
			else {
				// Add the shared instance.
				freshAdvisors.add(advisor);
			}
		}
		return freshAdvisors;
	}

	/**
	          
	 */
	private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
		String[] globalAdvisorNames =
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class); //    Advisor
		String[] globalInterceptorNames =
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class); //    Interceptor
		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);
			}
		}
	}

	/**
	 *  advice      ,  Advice      
	 */
	private void addAdvisorOnChainCreation(Object next, String name) {
		Advisor advisor = namedBeanToAdvisor(next);
		if (logger.isTraceEnabled()) {
			logger.trace("Adding advisor with name '" + name + "'");
		}			
		addAdvisor(advisor);
	}
	
	private TargetSource freshTargetSource() {
		if (this.targetName == null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");
			}
			return this.targetSource;
		}
		else {
			if (this.beanFactory == null) {
				throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
						"- cannot resolve target with name '" + this.targetName + "'");
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Refreshing target with name '" + this.targetName + "'");
			}
			Object target = this.beanFactory.getBean(this.targetName);
			return (target instanceof TargetSource ? (TargetSource) target : new SingletonTargetSource(target));
		}
	}

	/**
	 * Advisor or Advice    Advisor
	 */
	private Advisor namedBeanToAdvisor(Object next) {
		try {
			return this.advisorAdapterRegistry.wrap(next);
		}
		catch (UnknownAdviceTypeException ex) {
			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);
		}
	}

	@Override
	protected void adviceChanged() {
		super.adviceChanged();
		if (this.singleton) {
			logger.debug("Advice has changed; recaching singleton instance");
			synchronized (this) {
				this.singletonInstance = null;
			}
		}
	}



	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
		// Rely on default serialization; just initialize state after deserialization.
		ois.defaultReadObject();

		// Initialize transient fields.
		this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
	}


	/**
	 * Used in the interceptor chain where we need to replace a bean with a prototype
	 * on creating a proxy.
	 */
	private static class PrototypePlaceholderAdvisor implements Advisor, Serializable {

		private final String beanName;

		private final String message;
		
		public PrototypePlaceholderAdvisor(String beanName) {
			this.beanName = beanName;
			this.message = "Placeholder for prototype Advisor/Advice with bean name '" + beanName + "'";
		}
		
		public String getBeanName() {
			return beanName;
		}
		
		public Advice getAdvice() {
			throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);
		}
		
		public boolean isPerInstance() {
			throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);
		}
		
		@Override
		public String toString() {
			return this.message;
		}
	}

}