Insider of Spring Technology 3 - Principle of Spring AOP (2)

Continue with Blog: Spring Technology Insider 3 - Spring AOP Principle (1)

https://my.oschina.net/guanhe/blog/1476138

Spring Aop is eventually converted to JdkDynamicAopProxy or Objenesis CglibAopProxy to invoke the object as an entry

The entry of JdkDynamicAopProxy is invoke function, and the entry of Objenesis CglibAopProxy is the intercept method of DynamicAdvisedInterceptor. Ultimately, they are all proceed methods that are converted into Reflective Method Invocation.

Let's look at the source code of proceed method:

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

Based on the previous interceptor chain matching, we can see here that it traverses all interceptors and Dynamic Method Matchers, so where does interceptors and Dynamic Method Matchers come from? Let's keep looking back.

In our previous configuration, we configured the interceptor Names property for ProxyFactoryBean. During initializeAdvisorChain() initializing the AdvisorChain chain, we injected the Bean object in interceptoeNames as Advisor.

In AdvisedSupport's List collection of advisors, we know that ProxyFactoryBean is also a subclass of AdvisedSupport

Therefore:

@Override
	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.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

In this method, ProxyBeanFactory has been injected into JdkDynamicAopProxy or Objenesis CglibAopProxy, and we return to CglibAopProxy or JdkDynamicAopProxy.

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

From this, we can see that the interception chain on this side is the getInterceptors AndDynamicInterception Advice method in the proxyFactoryBean invoked, and because the ProxyFactoryBean inherits from the AdvisedSupport class, the final invocation is

The getInterceptors AndDynamicInterceptionAdvice method in DefaultAdvisorChainFactory.

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, Class<?> targetClass) {
		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		for (Advisor advisor : config.getAdvisors()) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		return interceptorList;
	}

config.getAdvisors().length is the length of the configuration of interceptor Names in ProxyFactoryBean, and we can see that it is used here.

       AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

As a registry, the real registry is the Default Advisor Adapter Registry. We can see that Spring uses a lot of involved patterns, separating the real implementation from the interface.

/**
	 * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
	 */
	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}
@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
	}

From the name, we can see that there are three Advice adapters registered here: MethodBeforeAdvice, AfterReturning Advice and ThrowAdvice. Let's look at the process of a specific adapter.

In MethodBeforeAdviceAdapter, adapter.getTnterceptor calls:

@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}
	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		return new MethodBeforeAdviceInterceptor(advice);
	}

The object returned is the MethodBeforeAdviceInterceptor.

So far, we have returned all relevant collections of Interceptor s. Let's look at the proceed method in Reflective Method Invocation:

if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}

The invoke method of the single Interceptor, Method BeforeAdvice Interceptor, AfterReturning Advice Interceptor and Throws Advice Interceptor, is called. Analyzing these three invoke methods, we can see that we implement the advice in aop aspect here, and implement the insertion interception before and after the method.

For example:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;
	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

To sum up:

Spring's Aop ultimately uses jdk reflection.

The main process is as follows:

ProxyFactoryBean --> getObject method --> getSingleton Instance method --> JdkDynamicAopProxy and Objenes CglibAopProxy interface call related invoke method and intercept method. The p method acts as the entrance of the proxy - > the proceed method which is finally transformed into Reflective Method Invocation - > the interceptor chain acquired before the proceed method is invoked for matching interception, and the Advice section of the proxy object is enhanced.

 

Relevant Processes of Supplementary Interceptor Chain

ProxyFactoryBean - > getObject method - > initializeAdvisorChain - > addAdvisorOnChainCreation () - > AdvisedSupport's addAdvisor() - > DefaultAdvisorChainFactory's getInterceptors AndDynamicInterception Advice - > DefaultAdvisorAdapter Registry's getInterceptor for adaptation and return the relevant interceptor ——> Call the relevant interceptor of the connector chain for interception

Keywords: Spring JDK

Added by nykoelle on Wed, 12 Jun 2019 03:01:49 +0300