1 overview

1.1 the sample

At the most basic level, after creating the business interface and implementation classes, configure < AOP :config>…. The
tag specifies < AOP :pointcut and < AOP: Advisor. The following is an example:

1.1.1 Creating interfaces and implementation classes

Interface:

public interface MockService {
    public String hello(String s);
}
Copy the code

Implementation class:

public class MockServiceImpl implements MockService {
    @Override
    public String hello(String s) {
        System.out.println("execute hello");
        returns; }}Copy the code

1.1.2 Implement method interception

Implementing an interface org. Aopalliance. Intercept. MethodInterceptor

public class CustomInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("CustomInterceptor before");
        Object result = invocation.proceed();
        System.out.println("CustomInterceptor after");
        returnresult; }}Copy the code

1.1.3 configuration XML

Create aop.xml and place it in the Resources directory:

<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
       default-lazy-init="false" default-autowire="byName">

    <! - implementation to org. Aopalliance. Intercept. MethodInterceptor interceptors -- -- >
    <bean id="customInterceptor" class="com.xxx.yyy.CustomInterceptor"/>

    <bean id="mockService" class="com.xxx.yyy.MockServiceImpl"/>

    <aop:config proxy-target-class="true">
        <aop:pointcut id="interceptorPointCuts" expression="execution(* com.xxx.yyy.. *. * (..) )"/>
        <aop:advisor advice-ref="customInterceptor" pointcut-ref="interceptorPointCuts"/>
    </aop:config>
</beans>
Copy the code

1.1.4 run

public class Main {

    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
        MockService mockService = (MockService) context.getBean("mockService");
        mockService.hello("mock"); }}Copy the code

Returns:

CustomInterceptor before
execute hello
CustomInterceptor after
Copy the code

1.2 AOP implementation process

Spring environment, in the process of start is called AbstractApplicationContext. Refresh (), AOP implementation process, also is to start from here.

  • 1 inobtainFreshBeanFactory()During execution, loadaop.xmlAnd according to thenamespacefindaopThe correspondingNamespaceHandler:AopNamespaceHandler;
  • 2 AopNamespaceHandler, found inconfigLabel correspondingBeanDefinitionParserThat is, the implementation object ofConfigBeanDefinitionParser;
  • 3 performConfigBeanDefinitionParser.parse, has two functions:
    1. In order toAspectJAwareAdvisorAutoProxyCreatorRegistered BeanDefinition;
    2. parsingpointcut.advisorAnd register the related object as a BeanDefinition.
  • 4 Register BeanPostProcessor:AspectJAwareAdvisorAutoProxyCreatorIs an implementation class for BeanPostProcessorAbstractAutoProxyCreatorThe subclass. After registering with BeanPostProcessor,AspectJAwareAdvisorAutoProxyCreatorIs called during Spring’s proxy creation of the bean.
  • 5. Create proxy and enhance it with Advisor.
    1. Create a proxy;
    2. Find matching advisors;
    3. Enhance the agent.

2 AopNamespaceHandler

Spring environment load, you need to call AbstractApplicationContext. Refresh ().

The refresh () method, execution ConfigurableListableBeanFactory the beanFactory = obtainFreshBeanFactory (); When the BeanFacotry is created, the XML resource is loaded and parsed.

In the process, will call BeanDefinitionParserDelegate. ParseCustomElement extend tags parsing:

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
                / / get the namespace
		String namespaceUri = getNamespaceURI(ele);
		Handlers fetch the corresponding NamespaceHandler according to the meta-INF /spring.handlers file
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		// Call the namespaceHandler. parse method to return BeanDefinition
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

Copy the code

For details, please refer to the source code analysis and implementation of Spring custom tag configuration.


For
, Spring goes to the meta-INF/Spring.Handlers file according to XMLNS to find the corresponding namespace resolution class: http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler.

: in the AopNamespaceHandler registerBeanDefinitionParser (” config “, new ConfigBeanDefinitionParser ());

So:

  • aopThe parse class for namespace isAopNamespaceHandler
  • <aop:config/>The parse class for the tag isConfigBeanDefinitionParserIn theConfigBeanDefinitionParser,<aop:config/>The individual elements defined are resolved toBeanDefinition

3 ConfigBeanDefinitionParser

ConfigBeanDefinitionParser BeanDefinitionParser interface is achieved, the parse (Element Element, ParserContext ParserContext) method, to realize the function of two parts:

  • 1 Register a BeanDefinition with the Spring environment:AspectJAwareAdvisorAutoProxyCreator;
  • 2 Parse XML configuration pointcuts, advisors, and so on into a series of Beandefinitions.
@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);

        / / registered AspectJAwareAdvisorAutoProxyCreator of BeanDefinition
		configureAutoProxyCreator(parserContext, element);

		List<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			if (POINTCUT.equals(localName)) {
			    / / parsing pointcut
				parsePointcut(elt, parserContext);
			}
			else if (ADVISOR.equals(localName)) {
			    / / advisor
				parseAdvisor(elt, parserContext);
			}
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}
Copy the code

Among them:

private static final String POINTCUT = "pointcut";
private static final String ADVISOR = "advisor";
private static final String ASPECT = "aspect";
Copy the code

3.1 AspectJAwareAdvisorAutoProxyCreator

3.1.1 role

  • AspectJAwareAdvisorAutoProxyCreatorisAbstractAutoProxyCreatorThe subclass.
  • Abstractautoxycreator implements the interfaceBeanPostProcessor;
  • AbstractAutoProxyCreator inpostProcessAfterInitializationIn the implementation of thewrapIfNecessaryDo bean proxying.
@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if(bean ! =null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
	}
Copy the code

Spring calls BeanPostProcessor to process beans before and after they are generated during bean instantiation. Aop takes advantage of this:

Call AbstractAutoProxyCreator postProcessAfterInitialization method, according to the pointcut find corresponding advisor, agent on the bean.

3.1.2 registered BeanDefinition

Code execution flow:

  • 1 ConfigBeanDefinitionParser.configureAutoProxyCreator;

  • 2 AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);

    	public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) {
    
          / / register BeanDefinition
      	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
      			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
      	/ / set the class - proxy
      	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
      	registerComponentIfNecessary(beanDefinition, parserContext);
      }
    Copy the code
  • 3 AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary;

  • 4 AopConfigUtils.registerOrEscalateApcAsRequired:

public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";
			
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		//// omit code
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
Copy the code

The resulting AspectJAwareAdvisorAutoProxyCreator BeanDefinition, BeanName is org. Springframework. Aop. Config. InternalAutoProxyCreator.

At the same time, useClassProxyingIfNecessary method, according to * * aop: proxy in the config / * * – target – class, A parent class set up AspectJAwareAdvisorAutoProxyCreator ProxyConfig proxyTargetClass attributes.

3.2 analytical pointcut

, the registered AbstractExpressionPointcut BeanDefinition.

3.2.1 parsePointcut

	private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
		String id = pointcutElement.getAttribute(ID);
		
		Expression ="execution(* com.xxx.yyy.. *. * (..) )"
		String expression = pointcutElement.getAttribute(EXPRESSION);

		AbstractBeanDefinition pointcutDefinition = null;
		try {
			this.parseState.push(new PointcutEntry(id));
			
			/ / using AspectJExpressionPointcut, create BeanDefinition for pointcut,
			pointcutDefinition = createPointcutDefinition(expression);
			pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

			String pointcutBeanName = id;
			if (StringUtils.hasText(pointcutBeanName)) {
			     / / id as beanName registered AspectJExpressionPointcut of beans.
				parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
			}
			else {
			    / / to automatically generate beanName registered AspectJExpressionPointcut of beans.
				pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
			}
			parserContext.registerComponent(
					new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
		}
		finally {
			this.parseState.pop();
		}

		return pointcutDefinition;
	}
Copy the code

3.2.2 createPointcutDefinition

  • 1 aop:pointcutResolve toAspectJExpressionPointcutObject.
  • 2 AspectJExpressionPointcut extends AbstractExpressionPointcut
  • 3 expressionisAbstractExpressionPointcutThe properties of the
	protected AbstractBeanDefinition createPointcutDefinition(String expression) {
		RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
		beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
		beanDefinition.setSynthetic(true);
		beanDefinition.getPropertyValues().add(EXPRESSION, expression);
		return beanDefinition;
	}
Copy the code

3.3 analytical advisor

< AOP :advisor advisor-ref =”customInterceptor” pointcut =”interceptorPointCuts”/> Registered DefaultBeanFactoryPointcutAdvisor BeanDefinition.

3.3.1 parseAdvisor

  • 1 callcreateAdvisorBeanDefinitionCreate the advisor;
  • 2 callparsePointcutPropertyFor pointcut.
	private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
	
	    / / 1 create bean: DefaultBeanFactoryPointcutAdvisor
		AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
		String id = advisorElement.getAttribute(ID);

		try {
			this.parseState.push(new AdvisorEntry(id));
			String advisorBeanName = id;
			
			/ / 2 registered bean: DefaultBeanFactoryPointcutAdvisor
			if (StringUtils.hasText(advisorBeanName)) {
				parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
			}
			else {
				advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
			}

            // interceptorPointCuts ="interceptorPointCuts"
			Object pointcut = parsePointcutProperty(advisorElement, parserContext);
			if (pointcut instanceof BeanDefinition) {
			    / / return a ` pointcut ` structure of BeanDefinition (AspectJExpressionPointcut object), Is set ` DefaultBeanFactoryPointcutAdvisor. Pointcut = pointcut `
				advisorDef.getPropertyValues().add(POINTCUT, pointcut);
				parserContext.registerComponent(
						new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
			}
			else if (pointcut instanceof String) {
			   / / returns the beanName, set ` DefaultBeanFactoryPointcutAdvisor. Pointcut ` Bean references for a runtime.
				advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
				parserContext.registerComponent(
						newAdvisorComponentDefinition(advisorBeanName, advisorDef)); }}finally {
			this.parseState.pop(); }}Copy the code

3.3.2 rainfall distribution on 10-12createAdvisorBeanDefinition

  • 1 createDefaultBeanFactoryPointcutAdvisorBeanDefinition DefaultBeanFactoryPointcutAdvisor isPointcutAdvisorAn implementation of;
  • 2 parsingadvice-refGet the beanName of the advisor’s Bean, the customInterceptor in aOP.xml.
  • 3 DefaultBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor, the use ofadvice-refSet up theadviceBeanNameProperty, that is, the precedingcustomInterceptor.
    private static final String ADVICE_BEAN_NAME = "adviceBeanName";
    
	private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
	
	    / / create a ` DefaultBeanFactoryPointcutAdvisor ` BeanDefinition;
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(advisorElement));

        // Parse 'advice-ref' beanName of the Bean that gets advice;
		String adviceRef = advisorElement.getAttribute(ADVICE_REF);
		if(! StringUtils.hasText(adviceRef)) { parserContext.getReaderContext().error("'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
		}
		else {
		    / / set AbstractBeanFactoryPointcutAdvisor adviceBeanName attributes
			advisorDefinition.getPropertyValues().add(
					ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
		}

		if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
		}

		return advisorDefinition;
	}
Copy the code

3.3.3 parsePointcutProperty

  • 1 attribute haspointcut, use the expression to invoke createPointcutDefinition, after constructing AspectJExpressionPointcut bean returned directly.
  • 2 Otherwise returnpointcut-refThe specified bean acts as a Pointcut.

Pointcut takes precedence over pointcut-ref.

	private Object parsePointcutProperty(Element element, ParserContext parserContext) {
		if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
			parserContext.getReaderContext().error(
					"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
					element, this.parseState.snapshot());
			return null;
		}
		else if (element.hasAttribute(POINTCUT)) {
			
			/ / attributes have ` pointcut `, createPointcutDefinition expression calls after constructing AspectJExpressionPointcut bean returned directly.
			String expression = element.getAttribute(POINTCUT);
			AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
			pointcutDefinition.setSource(parserContext.extractSource(element));
			
			/ / return BeanDefinition
			return pointcutDefinition;
		}
		else if (element.hasAttribute(POINTCUT_REF)) {
			String pointcutRef = element.getAttribute(POINTCUT_REF);
			if(! StringUtils.hasText(pointcutRef)) { parserContext.getReaderContext().error("'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
				return null;
			}
			// Returns the beanName of pointcut-ref
			return pointcutRef;
		}
		else {
			parserContext.getReaderContext().error(
					"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
					element, this.parseState.snapshot());
			return null; }}Copy the code

3.4 BeanDefinitions registered during Parsing

  • BeanPostProcessor : AspectJAwareAdvisorAutoProxyCreatorBeanName isorg.springframework.aop.config.internalAutoProxyCreator;
  • Pointcut:AbstractExpressionPointcut, the expression attribute is set.
  • Advisor:DefaultBeanFactoryPointcutAdvisorThe pointcut property is set toAbstractExpressionPointcut.

4 registered BeanPostProcessor

In AbstractApplicationContext. Refresh () method, create ConfigurableListableBeanFactory, Performs registerBeanPostProcessors registered BeanPostProcessor with the Spring environment.

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
Copy the code

AspectJAwareAdvisorAutoProxyCreator at this time is added to used for processing bean created BeanPostProcessor list.

The brief process is as follows:

  • 1 callPostProcessorRegistrationDelegate.registerBeanPostProcessors;
  • 2 bybeanFactory.getBean(ppName, BeanPostProcessor.class);Get the List of BeanPostProcessors;
  • 3 performbeanFactory.addBeanPostProcessor(postProcessor).

5 Create beans and enhance them

5.1 createProxy

Spring to create Bean, is in AbstractAutowireCapableBeanFactory doCreateBean method:

  1. inAbstractAutowireCapableBeanFactory.doCreateBeanCall theinitializeBean:
// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); }}Copy the code
  1. ininitializeBeanIn:
if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }Copy the code
  1. applyBeanPostProcessorsAfterInitializationPerform the BeanPostProcessor. PostProcessAfterInitialization method:
@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
Copy the code
  1. AbstractAutoProxyCreator.postProcessAfterInitializationExecute here:
@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if(bean ! =null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
	}
Copy the code
  1. inwrapIfNecessaryExecute createProxy with advisor in:
// Create proxy if we have advice.

        // 1 Find advisor
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 2 Create proxy and enhance it with advisor
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
Copy the code

5.2 Searching for matching Advisors

AbstractAutoProxyCreator getAdvicesAndAdvisorsForBean is an abstract method, by the subclass AbstractAdvisorAutoProxyCreator implementation.

AbstractAdvisorAutoProxyCreator. GetAdvicesAndAdvisorsForBean call findEligibleAdvisors, implement two main processes:

  • 1. Obtain candidate advisors;
  • 2 Filter out matched advisors.
    /* beanClass: the beanName of the bean being proxied */
	protected List<Advisor> findEligibleAdvisors(Class
        beanClass, String beanName) {
	    // 1 Get the candidate advisors
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 2 Filter out matching advisors
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if(! eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); }return eligibleAdvisors;
	}
Copy the code

5.2.1 findCandidateAdvisors

Call BeanFactoryAdvisorRetrievalHelper findAdvisorBeans, access to all interface realized the Advisor Bean, main code snippet below:

  • 1 find beanName that implements Advisor interface:

    advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);

  • BeanName = beanName;

    List<Advisor> advisors = newLinkedList<>(); . advisors.add(this.beanFactory.getBean(name, Advisor.class)); .return advisors;
    Copy the code

5.2.2 findAdvisorsThatCanApply

Filter out the matching Advisor, mainly through AopUtils findAdvisorsThatCanApply, call canApply implementation:

public static List<Advisor> findAdvisorsThatCanApply(List
       
         candidateAdvisors, Class
         clazz)
        {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new LinkedList<>();
		for (Advisor candidate : candidateAdvisors) {
		    / / call canApply
			if (candidate instanceofIntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); }}booleanhasIntroductions = ! eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			/ / call canApply
			if(canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); }}return eligibleAdvisors;
	}
Copy the code

5.2.3 requirescanApply

  • 1 If the interface isIntroductionAdvisorIn the judgement, call the IntroductionAdvisor. ClassFilter. Matchs;
  • 2 If the interface isPointcutAdvisor(such as DefaultBeanFactoryPointcutAdvisor created earlier), the first call PointcutAdvisor. ClassFilter. Matches judging, The judgement MethodMatcher again. GetMethodMatcher ().
public static boolean canApply(Advisor advisor, Class<? > targetClass,boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true; }}public static boolean canApply(Pointcut pc, Class<? > targetClass,boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		if(! pc.getClassFilter().matches(targetClass)) {return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceofIntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<? >> classes =new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		classes.add(targetClass);
		for(Class<? > clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);for (Method method : methods) {
				if((introductionAwareMethodMatcher ! =null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true; }}}return false;
	}
Copy the code

5.3 Enhance the agent with advisor

In AbstractAutoProxyCreator. CreateProxy in implementation:

  • 1 create ProxyFactory
  • 2 determine proxyTargetClass
  • 3 buildAdvisors
  • 4 implement getProxy
protected Object createProxy(Class
        beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

        / / create ProxyFactory
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

        / / determine proxyTargetClass
		if(! proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else{ evaluateProxyInterfaces(beanClass, proxyFactory); }}// buildAdvisors
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

        / / getProxy execution
		return proxyFactory.getProxy(getProxyClassLoader());
	}
Copy the code

5.3.1 DefaultAopProxyFactory.createAopProxy

Proxyfactory. getProxy requires an AopProxy to implement AopProxy. Creating AopProxy in DefaultAopProxyFactory returns a JdkDynamicAopProxy or a CglibAopProxy.

@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 newJdkDynamicAopProxy(config); }}Copy the code

5.3.2 JdkDynamicAopProxy

JdkDynamicAopProxy implements the Java. Lang. Reflect. InvocationHandler interface, in the invoke (Object proxy, Method Method, the Object [] args) implemented in the proxy. The code snippet is as follows:

// Get the interception chain for this method.
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}
Copy the code

Call ReflectiveMethodInvocation. Proceed () implementation agent.

5.3.3 ObjenesisCglibAopProxy

ObjenesisCglibAopProxy is a subclass of CglibAopProxy. The proxy logic is implemented in CglibAopProxy.

CglibAopProxy derive Callback array, created DynamicAdvisedInterceptor object.

privateCallback[] getCallbacks(Class<? > rootClass){// omit the code
    // Choose an "aop" interceptor (used for AOP calls).
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    // omit the code
}
Copy the code

DynamicAdvisedInterceptor implements org. Springframework. Additional. Proxy. MethodInterceptor interfaces, perform in the intercept method agent:

// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
Copy the code

CglibMethodInvocation is a subclass of ReflectiveMethodInvocation, so is also called ReflectiveMethodInvocation. Proceed () implementation agent.