Aop: Section-oriented programming that extracts all code unrelated to core business logic, places it in a centralized location, and then dynamically weavers this common code into the container at runtime

1 Use of Spring AOP

Note: The Spring AOP usage section uses a normal Spring application as an example. (Non-Springboot applications)

Maven rely on

Spring applications:

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> < version > 5.1.18. RELEASE < / version > < / dependency > < the dependency > < groupId > aopalliance < / groupId > <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> < artifactId > aspectjweaver < / artifactId > < version > 1.9.1 < / version > < / dependency > < the dependency > < the groupId > org. Springframework < / groupId > < artifactId > spring - aspects < / artifactId > < version > 5.1.18. RELEASE < / version > </dependency>Copy the code

Springboot application

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> < version > 2.2.11. RELEASE < / version > < / dependency >Copy the code

1.1 Enabling Spring AOP

1.1.1 Spring Application Enabling AOP (Annotated Version)

Projects that use the SSM framework are Spring applications (as opposed to SpringBoot)

Turn aop on with the @enableAspectJAutoProxy annotation on the configuration class

Spring aop @enableAspectJAutoProxy @configuration Public class AopConfiguration {}Copy the code

1.1.2 Springboot Application Start SOP

The SpringBoot application turns aop on by default. The meta-INF /spring.factories file in the spring-boot-autoconfigure classpath introduces the AopAutoConfiguration automatic configuration class. The @enableAspectJAutoProxy annotation is used in the AopAutoConfiguration class.

1.2 Writing the section class

@pointcut ("execution(public int) "); / / @pointcut ("execution(public int) "); / / @pointcut ("execution(public int) ") com.dyzwj.aop.MathCalculator.div(..) )") public void pointcut(){} @Before("pointcut()") public void logStart(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); System.out.println(""+ JoinPoint.getSignature ().getName()+" Run... @before: The argument list is: {"+ arrays.asList (args)+"}"); } / / class reference @ After (" com. Dyzwj. Aop. LogAspects. Pointcut () ") public void logEnd (JoinPoint JoinPoint) { Println (""+ JoinPoint.getSignature ().getName()+" End... @After"); } @afterreturning (value = "pointcut()",returning = "result") public void logReturn(JoinPoint JoinPoint, Object result){system.out.println (""+joinPoint.getSignature().getName()+" {"+result+"}"); } @AfterThrowing(value = "pointcut()",throwing = "exception") public void logException(JoinPoint joinPoint,Exception {system.out.println (""+ JoinPoint.getSignature ().getName()+" {"+exception+"}"); }}Copy the code

1.3 Business Logic Code (Target Class)

Public class MathCalculator {public int div(int I,int j){system.out.println ("MathCalculator... div..." ); return i/j; } // Consider: does calling the aa() method trigger the aspect logic in conjunction with the configuration of the aspect class's pointcut expression? Public void aa(int I,int j){// system.out.println (this); this.div(i,j); }}Copy the code

1.4 configuration

Spring aop @enableAspectJAutoProxy @Configuration Public class AopConfiguration {// Add the business logic class to the container @bean public MathCalculator mathCalculator(){ return new MathCalculator(); } @bean public LogAspects LogAspects() {return new LogAspects(); } @Bean public AA aa(){ return new AA(); }}Copy the code

1.5 Implement target method

Public class AopMain {public static void main (String [] args) {/ / manually create AnnotationConfigApplicationContext annotated version of the container annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AopConfiguration.class); MathCalculator bean = annotationConfigApplicationContext.getBean(MathCalculator.class); // System.out.println(bean); // System.out.println(AopUtils.isAopProxy(bean)); / / bean. Aa (1, 2); //System.out.println(); Bean. Div (10, 2); // AA bean = annotationConfigApplicationContext.getBean(AA.class); / / bean. Bb (1, 2); }}Copy the code

2 Spring AOP principles

Source code Version Description

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> < version > 5.1.18. RELEASE < / version > < / dependency >Copy the code

Spring supports the following proxy methods:

  • JDK dynamic proxy

  • Additional agent

2.1 @ EnableAspectJAutoProxy annotation

/ / class using the @ Import annotations Import AspectJAutoProxyRegistrar, the class implements the ImportBeanDefinitionRegistrar interface, Rewrite the registerBeanDefinitions @ Import () method (AspectJAutoProxyRegistrar. Class) public @ interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false; }Copy the code

AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** * Register, escalate, and configure the AspectJ auto proxy creator based on the value * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing * {@code @Configuration} class. */ @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {/ / registered beanDefinition = = AnnotationAwareAspectJAutoProxyCreator AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy ! = null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}}Copy the code

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary

public abstract class AopConfigUtils { /** * The bean name of the internally managed auto-proxy creator. */ public static final String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"; public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null); } public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } private static BeanDefinition registerOrEscalateApcAsRequired( Class<? > cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); / / if the current registry contains internalAutoProxyCreator if (registry. ContainsBeanDefinition (AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (! CLS. GetName () equals (apcDefinition getBeanClassName ())) {/ / if the current class not internalAutoProxyCreator int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); If (currentPriority < requiredPriority) {// If the index is greater than the existing internal automatic proxy constructor, the smaller the index, The higher priority apcDefinition. SetBeanClassName (CLS) getName ()); } } return null; } // If the current registry does not contain internalAutoProxyCreator, use the current class as the root definition RootBeanDefinition beanDefinition = new RootBeanDefinition(CLS); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }}Copy the code

AspectJAutoProxyRegistrar# registerBeanDefinitions to container registered bean id for internalAutoProxyCreator = = > AnnotationAwareAspectJAutoProxyCreator types of beans

2.2 AnnotationAwareAspectJAutoProxyCreator

/** ** Overview * 1, get advice methods and all Spring Advisor beans from all @AspectJ annotated aspect classes in the current application context; * to get all the advice method/advisor when AnnotationAwareAspectJAutoProxyCreator applied to each bean create task execution, but internal use the caching mechanism, so the real lookup process occurs only at first is invoked. When each bean is created, check whether the bean meets the criteria for creating a proxy. If so, obtain all advise that can be applied to the bean and generate a proxy object for the current bean. * the main logic for qualifying is AopUtils#findAdvisorsThatCanApply */ @suppresswarnings ("serial") public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { @Nullable private List<Pattern> includePatterns; @Nullable private AspectJAdvisorFactory aspectJAdvisorFactory; @Nullable private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder; @ Override protected void initBeanFactory (ConfigurableListableBeanFactory the beanFactory) {/ / base class method is used to initialize the beanFactory, The real logic is to construct a container that gets all super.initBeanFactory(beanFactory) from the container; // The following logic is to construct aspectJAdvisorsBuilder, For by reflection method derives from the container / / all beans with @aspectj annotate the if (this. AspectJAdvisorFactory = = null) {enclosing aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); } this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); } // Find all Spring Advisor Beans and @AspectJ-annotated beans in the container, @override protected List<Advisor> findCandidateAdvisors() {// Add all the Spring advisors Find according to superclass rules. /** * Use the base Spring Advisor lookup mechanism to find all Spring Advisors * in the container Is the parent class using the constructed BeanFactoryAdvisorRetrievalHelper Advisor from * container for all the Spring beans. */ List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder ! = null) {/** * Use aspectJAdvisorsBuilder to get all @AspectJ-annotated beans from the container, And put them into Advisor * / advisors in addAll (this) aspectJAdvisorsBuilder) buildAspectJAdvisors ()); } // The list advisors now contain all Spring Advisor Beans and @AspectJ-annotated beans in the container, // they now exist as advisors; } // Determine if the specified class is an infrastructure class: // 1. If the parent class isInfrastructureClass determines that it is an infrastructure class, it is assumed that it is; // 2. If this is an @aspect annotated class, consider it an infrastructure class; @override protected Boolean isInfrastructureClass(Class<? > beanClass) { return (super.isInfrastructureClass(beanClass) || (this.aspectJAdvisorFactory ! = null && this.aspectJAdvisorFactory.isAspect(beanClass))); }}Copy the code

Look at the AnnotationAwareAspectJAutoProxyCreator inheritance structure

AnnotationAwareAspectJAutoProxyCreator extends 
		AspectJAwareAdvisorAutoProxyCreator extends 
			AbstractAdvisorAutoProxyCreator extends 
				AbstractAdvisorAutoProxyCreator extends 
					AbstractAutoProxyCreator extends ProxyProcessorSupport  implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

Copy the code

Look from AnnotationAwareAspectJAutoProxyCreator inheritance structure, focusing on the rear processor (SmartInstantiationAwareBeanPostProcessor: Before and after bean initialization) and auto-assemble BeanFactory logic.

2.3 Automatic assembly of BeanFactory

AbstractAutoProxyCreator. SetBeanFactory () : implementation BeanFactoryAware setBeanFactory method of interface

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { private BeanFactory beanFactory; public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; }}Copy the code

AbstractAdvisorAutoProxyCreator. SetBeanFactory () : rewrite – > super. SetBeanFactory (); -> initBeanFactory(beanFactory);

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper; Override public void setBeanFactory(BeanFactory) {// Call the setBeanFactory method of the base class first super.setBeanFactory(beanFactory); / / requirements set by the beanFactory Spring bean container must use type ConfigurableListableBeanFactory, / / or an exception is thrown, Statement of the current AdvisorAutoProxyCreator only for types to work on ConfigurableListableBeanFactory / / container if (! (beanFactory instanceof ConfigurableListableBeanFactory)) { throw new IllegalArgumentException( "AdvisorAutoProxyCreator  requires a ConfigurableListableBeanFactory: " + beanFactory); } / / the above after setting the beanFactory checked type, initialize the beanFactory immediately initBeanFactory ((ConfigurableListableBeanFactory) the beanFactory); } // Initialize beanFactory, initialize logic: / / prepare one for the the beanFactory BeanFactoryAdvisorRetrievalHelperAdapter assigned to this. AdvisorRetrievalHelper, Used to obtain the Spring from the beanFactory Advisor (inform) protected void initBeanFactory (ConfigurableListableBeanFactory the beanFactory) {/ / Initialization from the container to obtain qualified Spring Advisor enclosing advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter (the beanFactory); }}Copy the code

AnnotationAwareAspectJAutoProxyCreator. InitBeanFactory () : rewrite

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { protected void InitBeanFactory (ConfigurableListableBeanFactory the beanFactory) {/ / base class method is used to initialize the beanFactory, The real logic is to construct a container that gets all super.initBeanFactory(beanFactory) from the container; // The following logic is to construct aspectJAdvisorsBuilder, For by reflection method derives from the container / / all beans with @aspectj annotate the if (this. AspectJAdvisorFactory = = null) {enclosing aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); } this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); }}Copy the code

Automatic assembly BeanFactory does two things:

  • Initialize BeanFactoryAdvisorRetrievalHelperAdapter: get the Spring from the beanFactory Advisor (notice)

  • Initialization BeanFactoryAspectJAdvisorsBuilderAdapter: by reflection from the container for all beans with @aspectj annotations

2.4 Spring Bean lifecycle

(1) create (including attribute assignment) : - single instance container startup when creating objects - multiple instances Each time you get to create objects. (2) the BeanPostProcessor postProcessBeforeInitialization initialization (3) : Object has been created, and assign a good value, called initialization method. (4) the BeanPostProcessor postProcessAfterInitialization destroyed (5) : - When the single-instance container is closed - the multi-instance container does not manage the multi-instance bean and does not call the destruction methodCopy the code
What is initialization? Spring supports the following initialization methods for beans: (1) @bean (initMethod,destroyMethod); (2) Make the bean implement InitializingBean definition initialization logic, to make DisposableBean definition destruction logic Spring does not recommend using InitializationBean to call its initialization method because it unnecessarily couples code to Spring (3) using the annotations provided by the JSR250 specification: Spring provides CommonAnnotationBeanPostProcessor responsible for support @ PostConstruct and @ PreDestroy - @ PostConstruct: After the bean is created and the property is assigned, perform initialization logic - @predestroy: Perform destruction logic before the container destroys the beanCopy the code

Since multiple initializations are supported, what is the order of these initializations?

  • @PostConstruct

  • InitializingBean

  • @Bean(initMethod)

2.5 Rear processor logic

In fact, Spring’s BeanPostProcessor runs through the life cycle of spring beans (BeanPostProcessor also has many sub-interfaces). The main functions are:

  • Inferential construction method
  • Prepare for circular dependencies
  • Properties into
  • aop

Now look at @ EnableAspectJAutoProxy to bean – AnnotationAwareAspectJAutoProxyCreator container import.

See the parts of the box, the father class AbstractAutoProxyCreator implements the BeanPostProcessor interface postProcessAfterInitialization method, in this method, to determine whether need to bean packaging (agents).

AbstractAutoProxyCreator# wrapIfNecessary source reading advice: first the agent’s whole process clear, to view the subclass implementation details, such as getAdvicesAndAdvisorsForBean method, finally followed their source again

2.5.1 Whether to Perform proxy

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean ! = null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) ! = bean) { /** * earlyProxyReferences.remove(cacheKey) ! If the bean is true, the bean has not yet been aop. * When dealing with cyclic dependencies, some beans that have completed AOP ahead of time are put in the earlyProxyReferences collection because aop has already been done, So there's no need for AOP at this point * The average bean at this point, Return wrapIfNecessary(bean, beanName, cacheKey); return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { Direct return if (StringUtils. HasLength (beanName) && enclosing targetSourcedBeans. The contains (beanName)) {return bean; If (boil.false. Equals (this.advisedBeans.get(cacheKey))) {return bean; } // determine a walk through the springAOP foundation building classes or those that need to be skipped, Marked as false, do not need to increase direct return if (isInfrastructureClass (bean. GetClass () | | shouldSkip (bean. GetClass (), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } /** * // get all the special interceptor objects for the bean. The return value array needs to be considered in three cases: * // 1. Return array has value: need to do proxy, use specialized interceptor and general interceptor * // 2. Return array with no value, empty: need to do proxy, use generic interceptor only * // 3. Return null: Don't to do for the current bean proxy * / / the current class getAdvicesAndAdvisorsForBean method is an abstract method, Concrete implementation is provided by implementation subclass * / / / get all the candidates of the current bean enhancer (i.e., the current bean conforms to the point of tangency expression) / / AbstractAdvisorAutoProxyCreator# getAdvicesAndAdvisorsForBean Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); If (specificInterceptors! = DO_NOT_PROXY) {// Save the current bean in the enhanced bean collection advisedBeans // flag enhanced to TRUE to indicate that the enhanced implementation of this.AdvisedBeans.put (cacheKey, Boolean.TRUE); Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // Save in proxyType this.proxytypes. put(cacheKey, proxy.getClass()); // Return a cglib-enhanced proxy object for the current component to the container. When the target method is executed, the proxy object will execute the notification method flow. } // If no enhancement exists, mark false, as cache, again to improve efficiency this.AdvisedBeans.put (cacheKey, Boolea.false); return bean; } protected Object createProxy(Class<? > beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource TargetSource) {/ / if it is ConfigurableListableBeanFactory interface (let's DefaultListableBeanFactory is the interface implementation class), Exposure to the target class if (this. The beanFactory instanceof ConfigurableListableBeanFactory) {/ / to the beanFactory - > beanDefinition define an attribute: K = AutoProxyUtils originalTargetClass, v = need to be agent of bean class AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); Proxyfactory.copyfrom (this); // If it is not the proxy target class if (! ProxyFactory. IsProxyTargetClass ()) {/ / if the beanFactory defines the agent for the target class (additional) if (shouldProxyTargetClass (beanClass, BeanName)) {/ / agency factory set the target class proxyFactory. SetProxyTargetClass (true); EvaluateProxyInterfaces (beanClass, proxyFactory); }} // Wrap all specialized interceptors for the current bean and general interceptors in the container into a Spring Advisor object // to create the final proxy object // build all Advisor interceptors that ultimately apply to the bean: // 1. Get a generic interceptor from the container // 2. Plus a specialized interceptor that applies only to the bean:  specificInterceptors Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // Save the advisors to proxyFactory proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); // Customize proxyFactory, The method #customizeProxyFactory is an empty method in this class. Proxyfactory.setfrozen (this.freezeProxy); proxyfactory.setfrozen (this.freezeProxy); If (advisorsPreFiltered ()) {/ / the default false, it has enhanced the prefiltering matching Advisor proxyFactory. SetPreFiltered (true); Proxyfactory.getproxy () return proxyFactory.getProxy()); } / / AnnotationAwareAspectJAutoProxyCreator# isInfrastructureClass rewrite the method protected Boolean isInfrastructureClass (Class <? > beanClass) { boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass); if (retVal && logger.isTraceEnabled()) { logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]"); } return retVal; } / / AspectJAwareAdvisorAutoProxyCreator# shouldSkip rewrite the method protected Boolean shouldSkip (Class <? > beanClass, String beanName) { return AutoProxyUtils.isOriginalInstance(beanName, beanClass); }}Copy the code

2.5.2 Proxy Logic

AbstractAdvisorAutoProxyCreator

/ * * * AbstractAdvisorAutoProxyCreator itself implements the base class definition of abstract method # getAdvicesAndAdvisorsForBean () is used to from the container for a bean available AOP Advice and Spring Advisor bean. * and AbstractAdvisorAutoProxyCreator to # getAdvicesAndAdvisorsForBean () only use the Spring container Advisor, without considering the AOP Advice. AbstractAdvisorAutoProxyCreator agreed a bean needs to be automatically agent is: the condition of the container there is at least one matched with the bean Spring Advisors. The matching logic for a bean matches a Spring Advisor bean in the container is as follows: 1, AbstractAdvisorAutoProxyCreator itself provides a method Boolean isEligibleAdvisorBean (String beanName) based on Advisor The bean name declares whether the Advisor meets the criteria (the default implementation of this method is always true, and subclasses can override the implementation of this method). The current APC will first screen out all Spring Advisors that meet the criteria as candidates. 2. From the above Spring Advisors candidates, use the annotation information on the bean class/method to filter again and select those Spring Advisors that match the current bean as the Spring Advisors that will be wrapped to the current bean. Have order requirements of Spring Advisor can implement interface org. Springframework. Core. Ordered interface, Because AbstractAdvisorAutoProxyCreator for eligible Spring sorting Advisor accordingly before the parcel to the target bean. */ @SuppressWarnings("serial") public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { @Nullable private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper; Override public void setBeanFactory(BeanFactory) {// Call the setBeanFactory method of the base class first super.setBeanFactory(beanFactory); / / requirements set by the beanFactory Spring bean container must use type ConfigurableListableBeanFactory, / / or an exception is thrown, Statement of the current AdvisorAutoProxyCreator only for types to work on ConfigurableListableBeanFactory / / container if (! (beanFactory instanceof ConfigurableListableBeanFactory)) { throw new IllegalArgumentException( "AdvisorAutoProxyCreator  requires a ConfigurableListableBeanFactory: " + beanFactory); } / / the above after setting the beanFactory checked type, initialize the beanFactory immediately initBeanFactory ((ConfigurableListableBeanFactory) the beanFactory); } protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { /** * // Prepare one for the the beanFactory BeanFactoryAdvisorRetrievalHelperAdapter assigned to this. AdvisorRetrievalHelper, * Used to get Spring Advisor(notifications) from beanFactory. * / / / initialized from the container to obtain qualified Spring Advisor enclosing advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory); } // Find all qualified advisors /Advice for a bean, if the result is null, Will not create the agent for the bean @ Override @ Nullable protected Object [] getAdvicesAndAdvisorsForBean (Class <? > beanClass, String beanName, @nullable TargetSource TargetSource) {// Get all Spring Advisors available in the container for beanClass,beanName // find the qualified enhancer (applicable to the current bean) List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); If (advisors. IsEmpty ()) {// Return null if no available Spring Advisor is found, indicating that no proxy should be created for the current bean. // DO_NOT_PROXY is a null constant, indicating that: Return DO_NOT_PROXY; // Do not create a proxy for the bean if no Advisor is found. } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors(Class<? > beanClass, String beanName) {// Find all candidate enhancers // Find all Spring Advisors bean components from the container as candidates, The result is not yet filtered for the current bean // The method #findCandidateAdvisors() in the current class is an abstract method, List<Advisor> candidateAdvisors = findCandidateAdvisors(); // Filter each candidate Spring Advisor against the current bean, List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // Extend the list of Spring Advisors that meet the conditions. The current implementation method is empty. // Subimplementation classes can override this method to extend extendAdvisors(eligibleAdvisors). if (! EligibleAdvisors. IsEmpty ()) {// Sort the enhancers. } return eligibleAdvisors; } protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper ! = null, "No BeanFactoryAdvisorRetrievalHelper available"); / / find advisor in container return enclosing advisorRetrievalHelper. FindAdvisorBeans (); } protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<? > beanClass, String beanName) {// ProxyCreationContext uses a ThreadLocal variable to hold the bean currently being proxy created, // During proxy creation, For example, when evaluating pointcut expressions, ProxyCreationContext is used. // Thus, the proxy creation of a bean must be done in the same thread. Can't across threads ProxyCreationContext. SetCurrentProxiedBeanName (beanName); // Check whether each advisor needs to delegate the logic applied to the bean to AopUtils. Here don't do in-depth analysis, return AopUtils. FindAdvisorsThatCanApply (candidateAdvisors beanClass); } the finally {/ / finished advisor and matching process of bean, remove ProxyCreationContext ProxyCreationContext. SetCurrentProxiedBeanName (null); } } /** * Return whether the Advisor bean with the given name is eligible * for proxying in the first place. * @param beanName the name of the Advisor bean * @return whether the bean is eligible */ protected boolean isEligibleAdvisorBean(String beanName) { return true; }}Copy the code

ProxyFactory

public class ProxyFactory extends ProxyCreatorSupport { public Object getProxy(@Nullable ClassLoader classLoader) { //JdkDynamicAopProxy: JDK dynamic proxy -> implement the interface //ObjenesisCglibAopProxy: Cglib dynamic proxy -> unimplemented interface return createAopProxy().getProxy(classLoader); }}Copy the code

AdvisedSupport

public class ProxyCreatorSupport extends AdvisedSupport { protected final synchronized AopProxy createAopProxy() { if (! this.active) { activate(); CreateAopProxy #createAopProxy return getAopProxyFactory().createAopProxy(this); }}Copy the code

2.5.3 Which agent mode is adopted

DefaultAopProxyFactory: AN AOP proxy factory that determines whether the target object should be JDK dynamic proxy or Cglib proxy

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @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."); } / / the JDK dynamic Proxy if (targetClass isInterface () | | Proxy. IsProxyClass (targetClass)) {return new JdkDynamicAopProxy (config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); }}}Copy the code

CglibAopProxy: Cglib creates a proxy

class CglibAopProxy implements AopProxy, Serializable {
   
    public Object getProxy(@Nullable ClassLoader classLoader) {
       if (logger.isTraceEnabled()) {
          logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
       }

       try {
          Class<?> rootClass = this.advised.getTargetClass();
          Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

          Class<?> proxySuperClass = rootClass;
          if (ClassUtils.isCglibProxyClass(rootClass)) {
             proxySuperClass = rootClass.getSuperclass();
             Class<?>[] additionalInterfaces = rootClass.getInterfaces();
             for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
             }
          }

          // Validate the class, writing log messages as necessary.
          validateClassIfNecessary(proxySuperClass, classLoader);

          // Configure CGLIB Enhancer...
          Enhancer enhancer = createEnhancer();
          if (classLoader != null) {
             enhancer.setClassLoader(classLoader);
             if (classLoader instanceof SmartClassLoader &&
                   ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
             }
          }
          enhancer.setSuperclass(proxySuperClass);
          enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
          enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
          enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

          //获取回调列表 (拦截器链)
          Callback[] callbacks = getCallbacks(rootClass);
          Class<?>[] types = new Class<?>[callbacks.length];
          for (int x = 0; x < types.length; x++) {
             types[x] = callbacks[x].getClass();
          }
          // fixedInterceptorMap only populated at this point, after getCallbacks call above
          enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
          enhancer.setCallbackTypes(types);

          // Generate the proxy class and create a proxy instance.
          //生成代理类以及创建代理
          return createProxyClassAndInstance(enhancer, callbacks);
       }
       catch (CodeGenerationException | IllegalArgumentException ex) {
          throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
                ": Common causes of this problem include using a final class or a non-visible class",
                ex);
       }
       catch (Throwable ex) {
          // TargetSource.getTarget() failed
          throw new AopConfigException("Unexpected AOP exception", ex);
       }
    }
    
    
   
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
       // Parameters used for optimization choices...
       // 对 expose-proxy 属性的处理
       boolean exposeProxy = this.advised.isExposeProxy();
       boolean isFrozen = this.advised.isFrozen();
       boolean isStatic = this.advised.getTargetSource().isStatic();

       // Choose an "aop" interceptor (used for AOP calls).
       /**
        * 将拦截器封装在 DynamicAdvisedInterceptor 中
        *
        *  链式调用
        */
       Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

       // Choose a "straight to target" interceptor. (used for calls that are
       // unadvised but can return this). May be required to expose the proxy.
       Callback targetInterceptor;
       if (exposeProxy) {
          targetInterceptor = (isStatic ?
                new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
       }
       else {
          targetInterceptor = (isStatic ?
                new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
       }

       // Choose a "direct to target" dispatcher (used for
       // unadvised calls to static targets that cannot return this).
       Callback targetDispatcher = (isStatic ?
             new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

       //主回调
       Callback[] mainCallbacks = new Callback[] {
             // 将拦截器链加入 Callback 中
             aopInterceptor,  // for normal advice
             targetInterceptor,  // invoke target without considering advice, if optimized
             new SerializableNoOp(),  // no override for methods mapped to this
             targetDispatcher, this.advisedDispatcher,
             new EqualsInterceptor(this.advised),
             new HashCodeInterceptor(this.advised)
       };

       Callback[] callbacks;

       // If the target is a static one and the advice chain is frozen,
       // then we can make some optimizations by sending the AOP calls
       // direct to the target using the fixed chain for that method.
       if (isStatic && isFrozen) {
          Method[] methods = rootClass.getMethods();
          Callback[] fixedCallbacks = new Callback[methods.length];
          this.fixedInterceptorMap = new HashMap<>(methods.length);

          // TODO: small memory optimization here (can skip creation for methods with no advice)

          /**
           * 遍历类中的所有方法
           */
          for (int x = 0; x < methods.length; x++) {
             Method method = methods[x];
             /**
              * 获取每个方法对应的拦截器链
              */
             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
             fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                   chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
             this.fixedInterceptorMap.put(methods.toString(), x);
          }

          // Now copy both the callbacks from mainCallbacks
          // and fixedCallbacks into the callbacks array.

          /**
           * 根据主回调和
           */
          callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
          System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
          System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
          this.fixedInterceptorOffset = mainCallbacks.length;
       }
       else {
          callbacks = mainCallbacks;
       }
       return callbacks;
    }

    
    //cglib创建代理对象的方式,感兴趣的可以研究一下
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
       enhancer.setInterceptDuringConstruction(false);
       enhancer.setCallbacks(callbacks);
       return (this.constructorArgs != null && this.constructorArgTypes != null ?
             enhancer.create(this.constructorArgTypes, this.constructorArgs) :
             enhancer.create());
    }
    
    

}
Copy the code

JDK DynamicaopProxy: JDK dynamic proxy

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } Class<? >[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); /** * this(JdkDynamicAopProxy) is an InvocationHandler object. The invocationHandler.invoke () method is called */ return proxy.newProxyInstance (classLoader, proxiedInterfaces, this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { if (! this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } else if (! this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } else if (! this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy);  setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); Class<? > targetClass = (target ! = null ? target.getClass() : null); /** * 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 Considerations or fancy proxying. /** * If the cleanup is empty just take the target method */ Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else {/** * If there is an interceptor chain, create a CglibMethodInvocation with the target object, target method, interceptor chain, etc. */ / We need to create a method Invocation... MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } // Massage return value if necessary. Class<? > returnType = method.getReturnType(); if (retVal ! = null && retVal == target && returnType ! = Object.class && 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; } 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 { if (target ! = null && ! targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); }}}}Copy the code

As you can see, whether additional agent or the JDK dynamic proxy, is agent logic encapsulated into the interceptor chain (chain of responsibility pattern), and is the first of the interceptor chain blocker DynamicAdvisedInterceptor, therefore, the target method executes, Will actually perform the interceptor chain of interceptors MethodInterceptor. The invoke method, namely DynamicAdvisedInterceptor. Invoke method, by DynamicAdvisedInterceptor propagated downward again.