After filtering the advisor, you can create aop

protected Object org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(
			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        //If BeanFactory is a Configurable Listable BeanFactory, expose the proxy object class
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
        //Creating an Agent Factory
		ProxyFactory proxyFactory = new ProxyFactory();
		//The proxy factory inherits the same ProxyConfig class as the current class
		//copy some configuration properties of the current class to the proxy factory
		proxyFactory.copyFrom(this);
        //Has it been designated as the proxy target class
		if (!proxyFactory.isProxyTargetClass()) {
		    //Check the properties of BeanDefinition, org. spring framework. aop. framework. autoproxy. AutoProxyUtils. preserveTargetClass
		    //If true, set up the cglib agent
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
			    //Get the interface. If there is no interface, proxyFactory.setProxyTargetClass(true)
			    //(*1*)
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
        //(*2*)
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		for (Advisor advisor : advisors) {
		    //Setting advisor in the agent factory
			proxyFactory.addAdvisor(advisor);
		}
        //Setting up target object wrapping that requires proxy
		proxyFactory.setTargetSource(targetSource);
		//Custom proxy factory, implemented by subclasses
		customizeProxyFactory(proxyFactory);
        //Set whether the proxy configuration is frozen or not. After frozen, the proxy configuration cannot be changed.
		proxyFactory.setFrozen(this.freezeProxy);
		//Whether to return pre-filtered advisor
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
        //Get the proxy object
		return proxyFactory.getProxy(getProxyClassLoader());
	}
	
	
	//(*1*)
	protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
	    //Get the interface for the current bean
		Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
		boolean hasReasonableProxyInterface = false;
		//Exclude some spring interfaces for configuration, such as Initializing Bean, Disposable Bean, Disposable Bean
		//groovy.lang.GroovyObject
		for (Class<?> ifc : targetInterfaces) {
			if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
					ifc.getMethods().length > 0) {
				//Represents an interface
				hasReasonableProxyInterface = true;
				break;
			}
		}
		//If there are interfaces, add interfaces for proxies
		if (hasReasonableProxyInterface) {
			// Must allow for introductions; can't just set interfaces to the target's interfaces only.
			for (Class<?> ifc : targetInterfaces) {
				proxyFactory.addInterface(ifc);
			}
		}
		else {
		    //If there is no interface, set it to cglib proxy
			proxyFactory.setProxyTargetClass(true);
		}
	}
	
	//(*2*)
	protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
		// Handle prototypes correctly...
		//Get advice on program settings, and if you don't implement Method Interceptor, use adapter adapters
		Advisor[] commonInterceptors = resolveInterceptorNames();

		List<Object> allInterceptors = new ArrayList<Object>();
		if (specificInterceptors != null) {
			allInterceptors.addAll(Arrays.asList(specificInterceptors));
			if (commonInterceptors.length > 0) {
			    //Is universal interception used first?
				if (this.applyCommonInterceptorsFirst) {
					allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
				}
				else {
					allInterceptors.addAll(Arrays.asList(commonInterceptors));
				}
			}
		}
		if (logger.isDebugEnabled()) {
			int nrOfCommonInterceptors = commonInterceptors.length;
			int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
			logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
					" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
		}
        
		Advisor[] advisors = new Advisor[allInterceptors.size()];
		for (int i = 0; i < allInterceptors.size(); i++) {
		    //Loop check advisor, if advisor returns directly, if Advice and Method Interceptor, then create DefaultPointcut Advisor
		    //The default advisor's cut-off point is Pointcut.TRUE, which means that the visitor is not refusing. If it's not MethodInterceptor, check to see if it is.
		    //public DefaultAdvisorAdapterRegistry() {
        	//	registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        	//	registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        	//	registerAdvisorAdapter(new ThrowsAdviceAdapter());
        	//}
        	//MethodBeforeAdvice, AfterReturning Advice, ThrowsAdvice have corresponding adapters, and advisor types are still packaged using the default Advisor
			advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
		}
		return advisors;
	}
	

Agent Factory Creates Agent

public Object org.springframework.aop.framework.ProxyFactory.getProxy(ClassLoader classLoader) {
        //(*1*)(*3*)
		return createAopProxy().getProxy(classLoader);
	}
	
	 //(*1*)
	 protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		//(*2*)
		//getAopProxyFactory() returns the DefaultAopProxyFactory object
		return getAopProxyFactory().createAopProxy(this);
	}
	
	//(*2*)
	public AopProxy org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(AdvisedSupport config) throws AopConfigException {
	    //If you have interfaces or are set to proxy target objects or use optimization strategies, use the cglib proxy
		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);
			}
			//cglib agent
			return new ObjenesisCglibAopProxy(config);
		}
		else {
		    //jdk dynamic proxy
			return new JdkDynamicAopProxy(config);
		}
	}
	
	//(* 3*) Let's call a dynamic agent to see
	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		//(*4*)
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		//Find equals and hashCode methods, if you find the tag this.equalsDefined = true; this.hashCodeDefined = true;
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		//Using JDK Dynamic Agent to Create
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

    

public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) {
        //Get the interface of the class from the configuration
		Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
		//If there is no interface
		if (specifiedInterfaces.length == 0) {
			// No user-specified interfaces: check whether target class is an interface.
			Class<?> targetClass = advised.getTargetClass();
			//If the target class that needs to be proxy is set, get the interface again
			if (targetClass != null) {
				if (targetClass.isInterface()) {
					advised.setInterfaces(targetClass);
				}
				else if (Proxy.isProxyClass(targetClass)) {
					advised.setInterfaces(targetClass.getInterfaces());
				}
				specifiedInterfaces = advised.getProxiedInterfaces();
			}
		}
		//Is there a SpringProxy interface in the interface to mark whether a class is proxy generated by spring? If not, then
	    //Spring automatically adds this interface to mark a class as a proxy class generated by spring
		boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
		//If the Advised interface is not defined and the proxy class is not prevented from being converted to Advised, spring automatically adds the interface
		boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
		int nonUserIfcCount = 0;
		//Number of Extended Agent Interfaces
		if (addSpringProxy) {
			nonUserIfcCount++;
		}
		//Number of Extended Agent Interfaces
		if (addAdvised) {
			nonUserIfcCount++;
		}
		Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
		System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
		//Add SpringProxy interface
		if (addSpringProxy) {
			proxiedInterfaces[specifiedInterfaces.length] = SpringProxy.class;
		}
		//Add Advised Interface
		if (addAdvised) {
			proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class;
		}
		return proxiedInterfaces;
	}

Okay, if you create a proxy, as we've already seen, let me now look at Jdk DynamicAopProxy, which implements JDK dynamic proxy This class implements the InvocationHandler interface of jdk, so we focus on its invoke method.

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Class<?> targetClass = null;
		Object target = null;

		try {
		    //Processing equals method
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			//Processing hashCode method
			if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			//If this.advised.opaque is false, spring automatically adds an Advised interface for the proxy class to implement
			//Determine whether the current method is defined in the interface, which is Advised's parent interface or itself
			//So reflection calls methods that target this.advised, which implements Advised
			if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				//Reflection calls, reflecting the target object is this.advised, which is a ProxyFactory object, which implements the Advised object.
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;
            //Determine whether the proxy class needs to be exposed, and if so, save the current proxy class in the current thread
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}
            
			// May be null. Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			//Get the proxy target object
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}

			// Get the interception chain for this method.
			//Get the interceptor chain of the current 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 there is no interceptor chain suitable for the corresponding method, the direct reflection call
			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...
				//Create a method call driver to drive chain execution
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				//Drive chain execution
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			//Get the return value of the method
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			//If the method returns to null instead of void, and the fucking basic type, then the error is thrown
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
		    //In general, singleton objects are static, so objects that will be recreated, such as those in prototype declaration cycle, are not static.
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				//Release target
				targetSource.releaseTarget(target);
			}
			//If the proxy object is exposed, the original value is set back to restore the scene.
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

Construction of Interceptor Chain

public List<Object> org.springframework.aop.framework.DefaultAdvisorChainFactory.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);
		//Get the class object of the class
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		//First, the introduction enhancement matching is performed, and all advisors are iterated. If there is an introduction enhancement advisor, then the class matching is performed, and if the matching returns true.
		//Otherwise false
		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
		//Getting the Advisor adapter registers, we saw earlier that some Advice s did not implement Method Interceptor and were packaged as DefaultPointcut.
		//So it needs to be adapted to MethodInterceptor.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        
		for (Advisor advisor : config.getAdvisors()) {
		    //Cut-point notifier, using cut-point to intercept aop
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				//If pre-filtering has been done, then there is no need to match the tangent points, otherwise the tangent points are matched again.
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				    //Getting the Method Interceptor is usually done directly from the advisor, but not all of the advice s have been implemented.
				    //MethodInterceptor interfaces, such as MethodBeforeAdvice, AfterReturning Advice, ThrowsAdvice
				    //So you need to adapt these advice s that do not implement Method Interceptor (adapter mode)
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					//Get a method matcher for matching methods
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					//Determine whether the current call method matches the cut point expression.
					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));
						}
					}
				}
			}
			//If the introduction enhances Advisor, then only class matching is required.
			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 {
			    //Other types of advisors are the same as the aforementioned post-method interception, except that no matching is required, because such advisors are typically
			    //DefaultPointcut, which is not bound to any tangent expression, defaults to Pointcut.TRUE
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

When the interceptor is ready, spring builds a driver, which is the Reflective Method Invocation we saw in the invoke method above. Let's look at its proceed method.

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		//spring uses a subscript current Interceptor Index to indicate where it is currently executing, if all interceptors are executed
		//Then you can call the join point method
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
        //Obtaining the corresponding subscript interceptor
		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);
		}
	}

Let's pick one of the interceptors to see how spring intercepts, such as AspectJAroundAdvice, which is a circular notification

public Object org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		//Wrapping method call information
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
		//Used as a parameter to pass to the join point, internal correlation ProxyMethod Invocation, we use the join point method
		//Call its process method to continue the call to the next notification
		//Users get connection point information, such as getting kind type, this (proxy object), target (proxy object), etc.
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		//JoinPoint Match is used to store matching information, parameter binding information
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		//Call notification method
		return invokeAdviceMethod(pjp, jpm, null, null);
	}

Call notification methods

protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t)
			throws Throwable {

		return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
	}
	
	
	protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
	    //Parametric binding, which we analyzed when we analyzed annotation advice acquisition, is not discussed here.
		calculateArgumentBindings();

		// AMC start
		Object[] adviceInvocationArgs = new Object[this.adviceInvocationArgumentCount];
		int numBound = 0;
        
        //If a join Point parameter exists, set jp to the specified parameter location
		if (this.joinPointArgumentIndex != -1) {
			adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
			numBound++;
		}
		//StaticPart parameter for static methods (static join points)
		else if (this.joinPointStaticPartArgumentIndex != -1) {
			adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
			numBound++;
		}
        
        //If the parameter binding is not null, it means that the parameter binding has been done, such as we specified the method variable name, the return value variable name, and the exception method name.
		if (!CollectionUtils.isEmpty(this.argumentBindings)) {
			// binding from pointcut match
			//If the connection point matching information exists, then get the binding parameter information execution (public com. zhipin. service. *. (.) & & args (a, b, c)) parsed from the tangent point.
			if (jpMatch != null) {
			    //Obtaining Tangent Point Parameters
				PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
				for (PointcutParameter parameter : parameterBindings) {
				    //Get the parameter name
					String name = parameter.getName();
					//Getting the position of the parameter from the parameter binding
					Integer index = this.argumentBindings.get(name);
					//Set the bound parameter value to the corresponding method parameter position
					adviceInvocationArgs[index] = parameter.getBinding();
					numBound++;
				}
			}
			// binding from returning clause
			//Set the return value
			if (this.returningName != null) {
			    //Get the subscript of the return value variable
				Integer index = this.argumentBindings.get(this.returningName);
				//Set the return value to the corresponding subscript position
				adviceInvocationArgs[index] = returnValue;
				numBound++;
			}
			// binding from thrown exception
			if (this.throwingName != null) {
			    //Binding throws exception parameter values
				Integer index = this.argumentBindings.get(this.throwingName);
				adviceInvocationArgs[index] = ex;
				numBound++;
			}
		}
        //If the number of parameters bound does not match the actual number of parameters, an exception is thrown
		if (numBound != this.adviceInvocationArgumentCount) {
			throw new IllegalStateException("Required to bind " + this.adviceInvocationArgumentCount +
					" arguments, but only bound " + numBound + " (JoinPointMatch " +
					(jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
		}
        //Returns a list of parameters
		return adviceInvocationArgs;
	}

When the parameters are ready, the corresponding notification method can be invoked.

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		//Handling cases without parameters
		if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
			actualArgs = null;
		}
		try {
		    //You'll see
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			// TODO AopUtils.invokeJoinpointUsingReflection
			//Do you remember this facet example factory? This example factory, which we analyzed earlier, actually calls the getBean method of BeanFactory to get the tangent object inside.
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("Mismatch on arguments to advice method [" +
					this.aspectJAdviceMethod + "]; pointcut expression [" +
					this.pointcut.getPointcutExpression() + "]", ex);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}

OK, the section method has been invoked, but we found that the circular notification did not invoke the proceed method of Joinpoint. For surround notification, we usually need to add a ProceedingJoinPoint type parameter on the notification method parameter, then call its proceed method in the code, and its proceed method calls the drive ReflectiveMethodInv again. The proceed method of location. Okay, aop knows this, and other announcements, if students are interested, they will study them by themselves.