Spring source code analysis (d) (AOP realization) (1)

Copyright Notice: Copyright: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/qq_37598011/article/details/89971937

    In Spring AOP implementation, the core technology is the use of dynamic proxy. You can create a proxy object to an arbitrary Java objects through dynamic proxy feature. In Spring it can be divided into specific JDK CGLIB agents and agents.

    There in Spring AOP this class is a core class ProxyFactoryBean, this class is created in the underlying application method Spring Ioc AOP environment, Spring completed package through this class of use AOP.

Establish AopProxy proxy object

    In ProxyFactoryBean, the configured attribute has been defined by interceptorNames notifier Advisor. In ProxyFactoryBean, the need to generate Proxy proxy object for the target audience, so do the preparatory work for the cross-section of the AOP weaving.
    ProxyFactoryBean AOP implementation or to rely on Proxy to JDK CGLIB provided. Get the object from FactoryBean, is getObject () method as the entry completed. For ProxyFactoryBean concerned, the need to increase the target audience enhancement processing, through getObject () method encapsulates, these enhancements provide processing services for the realization of AOP functionality. achieve getObject () as follows:

	public Object getObject() throws BeansException {
		//初始化通知器链
		initializeAdvisorChain();
		//对singleton和prototype类型做区分,生成对应的proxy
		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 () method of the first chain to initialize the notification, a series of notification package chain interceptor, interceptors must be read from the configuration, and then be ready to generate a proxy object. When generating a proxy object, because there are singleton Spring type and prototype two different types of Bean, so to generate a proxy object to make a distinction.

	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));
			}

			// Globals can't be last unless we specified a targetSource using the property...
			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");
			}

			// 添加Advisor链的调用,通过interceptorNames属性进行配置的
			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()));
				}

				else {
					// If we get here, we need to add a named interceptor.
					// We must check if it's a singleton or prototype.
					//如果程序在这里被调用,那么需要加入命名的拦截器advice,并检查这个bean是singleton还是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);
				}
			}
		}

		this.advisorChainInitialized = true;
	}

    Proxy Configuration Advisor chain initializeAdvisorchain proxy objects is done in the process, the initialization process has a flag advisorChainInitialized, this flag to indicate whether the notification chain initialized. If you have already initialized, then it will not be initialized, but directly returned. In other words, this initialization work occurred in the application for the first time to obtain the proxy object by ProxyFactoryBean time. After the completion of the initialization, and then reads all the notification configuration appears in this process is to get the notifier notifier's name getBean method to the container on it, this is done by a callback for IoC container implementation to complete. Is then taken from the vessel IoC added notifier notifies the chain, this is addAdvisorOnChainCreation () method to achieve.

    ok ~ Let's see how he acquired specific proxy object. 

    Back getObject () method to see him in the case of a single case is how to run, generating singleton proxy object to complete the code getSingletonInstance () in this method is to generate AopProxy ProxyFactoryBean proxy object call entry. Proxy object encapsulates the call to the target audience, that method calls for the behavior of the target object will be intercepted here generated proxy object. Specific generation process is to first read ProxyFactoryBean configuration, make the necessary preparations to generate proxy objects, such as setting the proxy method call interface. DETAILED Spring AopProxy generated proxy object class.
 

	private synchronized Object getSingletonInstance() {
		if (this.singletonInstance == null) {
			this.targetSource = freshTargetSource();
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
				//根据AOP框架来判断需要代理的接口
				// 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);
			//这里通过ProxyFactory来生成需要的Proxy
			this.singletonInstance = getProxy(createAopProxy());
		}
		return this.singletonInstance;
	}



    //通过AopProxy 返回来获取代理对象
	protected Object getProxy(AopProxy aopProxy) {
		return aopProxy.getProxy(this.proxyClassLoader);
	}


	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		//通过AopProxyFactory获取AopProxy,这个AopProxyFactory是在初始化中定义
		//使用的是DefaultAopProxyFactory
		return getAopProxyFactory().createAopProxy(this);
	}


	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (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.");
			}
			//如果targetClass是接口类,使用JDK来生成Proxy
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			//不是接口类,通过CGLIB生成
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}


    The Spring Framework AOP to achieve with the proxy object separated by AopProxy interface class, which has two specific implementations: JdkDynamicAopProxy and ObjenesisCglibAopProxy. These two subclasses are CGLIB Proxy proxy object and to generate a desired JDK.

    Specific proxy object generated by AopProxyFactory to CGLIB generated by or JDK. AopProxy generated proxy object, you need to consider which way to generate use, if the target object is an interface class, suitable for use JDK to generate a proxy object, otherwise it will use the Spring CGLIB proxy object to generate the target object. In order to meet the requirements of different proxy objects generated ,, DefaultAopProxyFactory production plant as AopProxy object, the object may be generated both AopProxy according to different needs.


JDK proxy object generated AopProxy

    Here you can see AopProxy implemented in two, respectively, based on the JDK JdkDynamicAopProxy and CGLIB-based ObjenesisCglibAopProxy.

	@Override
	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

    JdkDynamicAopProxy JDK Proxy class used to generate the proxy object, prior to generating Proxy objects need to obtain first proxy interface agent arranged advised object from the object, and then calls the newProxylnstance Proxy method, the finally obtained Proxy agent corresponding to the object. When generating a proxy object, need to specify three parameters, a class loader, is a proxy interface, the other one is Proxy callback methods where the object is, the object needs to achieve InvocationHandler interface. This Invocationhandler interface defines the invoke method, providing a callback entrance proxy object. For JdkDynamicProxy, which itself implements InvocationHandler interfaces and invoke () method, the invoke () method is the callback method Proxy proxy object, you can use this to put JdkDynamicAopProxy assigned to the Proxy object that is JdkDynamicAopproxy object itself, the Proxy Agent when the interface method is called, it will trigger a callback invoke () method, the callback method completes the package AOP weaving achieve.
 

CGLIB proxy object generated AopProxy

    In AopProxy interface can be seen CGLIB used to generate Proxy proxy object, the proxy object Proxy generation can be seen in the code for ObjenesisCglibAopProxy, the same is done in the implementation of AopProxy getProxy the interface. ObjenesisCglibAopProxy inherited CglibAopProxy rewriting createProxyClassAndInstance () method to instantiate objects without support by the constructor function.

	public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
		this.advisedDispatcher = new AdvisedDispatcher(this.advised);
	}

    For the realization of AOP can be seen as preparing the infrastructure and operation of the auxiliary two-part AOP generates AopProxy proxy object here can be seen as a static process AOP infrastructure built. Through this preparation process, these calls to be part of the proxy object, the interceptor is ready, waiting for the AOP process used in the operation of these infrastructures.

Guess you like

Origin blog.csdn.net/qq_37598011/article/details/89971937