This is the correct way to open the Springboot transaction creation process (with source code analysis)

SpringBoot transaction

Transactions are a relatively important part of Springboot. It is also a usage scenario of aop. Let's analyze the whole transaction creation process from the perspective of source code.

Many of the loads in the springboot startup process are common, so I won't talk about them in detail. For this part, please refer to the spring boot loading web container tomcat process source code analysis and spring boot integration mybatis source code analysis

For the process of generating proxy classes by enhancer, please refer to the annotation @ Configuration source code analysis in Springboot

Code path: springboot transaction

1. Auto load configuration

First, read the configuration class org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,

The method is to automatically load the value of key=org.springframework.boot.autoconfigure.EnableAutoConfiguration in \ META-INF\spring.factories in the configuration file spring-boot-autoconfigure-2.5.2.jar when starting through springboot. There is org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration.

When org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration is loaded, the internal classes are scanned and loaded.

The internal class EnableTransactionManagementConfiguration will be scanned here.

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(TransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {
		
		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		public static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}

At the same time, it will scan the JdkDynamicAutoProxyConfiguration and CglibAutoProxyConfiguration classes. By default, we do not configure the spring.aop.proxy-target-class attribute in the context, so only the CglibAutoProxyConfiguration class will be loaded, and then read the @ EnableTransactionManagement(proxyTargetClass = true) annotation, Continue to load the import annotation on the EnableTransactionManagement annotation class.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
//The import annotation here will be read to load the TransactionManagementConfigurationSelector class
public @interface EnableTransactionManagement {
	......
}

Let's look at the inheritance relationship of the transaction management configuration selector

It can be seen that the TransactionManagementConfigurationSelector inherits the AdviceModeImportSelector and indirectly implements the ImportSelector interface. Therefore, when loading the TransactionManagementConfigurationSelector, the method String[] selectImports(AnnotationMetadata importingClassMetadata) of the ImportSelector interface will be called; This interface is currently implemented in the AdviceModeImportSelector class.

Let's look at this part of the code

	//This code is in the AdviceModeImportSelector class
	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
        //This code is to get the generic parameter of the subclass AdviceModeImportSelector. What we get here is enable transaction management
        
		Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");

		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
        //This sentence is an object that gets the generic parameter annotation from the import class of the current class. What is obtained here is the value of the @ EnableTransactionManagement(proxyTargetClass = true) annotation on the CglibAutoProxyConfiguration class
        
		if (attributes == null) {
			throw new IllegalArgumentException(String.format(
					"@%s is not present on importing class '%s' as expected",
					annType.getSimpleName(), importingClassMetadata.getClassName()));
		}

		AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
        //This is to obtain the value of the model property. This property has the default value EnableTransactionManagement. The default value of the mode is AdviceMode.PROXY
        
		String[] imports = selectImports(adviceMode);
        //This code is implemented in the TransactionManagementConfigurationSelector class, which is also relatively simple. It returns the class name of the class to be loaded according to the value of adviceMode. Currently, the returned here is new string [] {autoproxyregister. Class. Getname(), 						 ProxyTransactionManagementConfiguration.class.getName()};
        //The AutoProxyRegistrar and ProxyTransactionManagementConfiguration classes will be loaded later
        
		if (imports == null) {
			throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
		}
		return imports;
	}

Let's take a look at the loading of autoproxyregister and ProxyTransactionManagementConfiguration

Autoproxyregister implements the importbeandefinitionregister interface. registerBeanDefinitions will be called when loading.

	//Methods of autoproxyregister
	//importingClassMetadata here can be considered as CglibAutoProxyConfiguration
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        //Here is to get the annotation on the CglibAutoProxyConfiguration class
        
        //It's relatively simple here. Get the annotations on the CglibAutoProxyConfiguration class in turn, and view the attribute mode and proxyTargetClass
		for (String annType : annTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
                    //Will eventually come here
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    //I won't go in here. This will add the beanDefinition of the class infrastructureasuggestorautoproxycreator.class in the registry
                    
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        //Here is the property ("proxyTargetClass", Boolean.TRUE) added and set the property of the finally generated infrastructure advisor autoproxycreator
						return;
					}
				}
			}
		}
		......
	}

ProxyTransactionManagementConfiguration is an ordinary Configuration configuration class. During loading, the beanmethod in it will also be scanned for loading. Several of these are also important. Let's take a look at its source code

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
//It will scan its internal beanmethod and load it. I won't discuss the use of this beanmethod here. I'll talk about it when I explain the transaction execution process
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    //Note: the two input parameters of this method are the bean objects of the following two beanmethod methods
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    //This class is mainly used to filter whether candidate classes can be used for transaction enhancement, and return the corresponding transaction attribute object
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    //This is mainly the transaction interceptor, and the transaction related will be handed over to it for processing
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

Here, let's take a look at the main loaded bean s

  • Infrastructure advisor autoproxycreator and BeanFactoryTransactionAttributeSourceAdvisor are mainly the two transactionattributesource and transactioninterceptor that are injected into BeanFactoryTransactionAttributeSourceAdvisor. They should not be mentioned separately, but can be obtained through BeanFactoryTransactionAttributeSourceAdvisor

2. Infrastructureasuggestorautoproxycreator class

Let's look at the inheritance relationship of infrastructure advisor autoproxycreator

The inheritance relationship of this class is relatively complex. Let's only select what we are most concerned about to analyze.

As can be seen from the figure, the infrastructureasuggestorautoproxycreator class indirectly implements the BeanPostProcessor interface, which is mainly used to enhance each bean object before and after initialization. Call postProcessBeforeInitialization before every bean initialization, and then call postProcessAfterInitialization after initialization.

Note: before and after bean initialization is not before and after object creation. These operations must be after object creation

3.BeanFactoryTransactionAttributeSourceAdvisor class

Let's now look at the BeanFactoryTransactionAttributeSourceAdvisor class, and first look at its inheritance relationship

You can see that this class also implements the Advisor interface, which is mainly used to host Advice, and Advice is mainly used as an interceptor.

At the same time, this class also implements PointcutAdvisor, which can return Pointcut, which can be used to filter which methods need to be intercepted

4. Judge whether the bean object needs transaction enhancement

After the bean is initialized, it will also call the infrastructure advisor autoproxycreator.postprocessafterinitialization method (in the AbstractAutoProxyCreator class). The wrapIfNecessary method is then called. Let's see this method

	//Methods in AbstractAutoProxyCreator class
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
        //From the above English comments, you can easily understand that aop is generated here, and the corresponding transactions are actually completed by aop. Let's focus on the code here.
        //Our @ Transactional annotation is on the UserServiceImpl class, so we can only focus on the execution process of this class. Let's go into this method
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        //This specificInterceptors is mainly an Advisor. This is not empty. It means that the current bean object can be aop proxy by specificInterceptors, and then enter the createProxy inside for aop enhancement
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
            //Here, the proxy class will be generated and the proxy object will be returned
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
@Override
@Nullable
//This method is mainly used to find the applicable advice and advisor according to the bean we passed in. If the returned is empty, it means that AOP enhancement is not required,
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
   
   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
   }
   return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   //This sentence is relatively simple. It is mainly to obtain the corresponding bean of type Advisor.class in beanFactory. This is also relatively simple. Just jump in and have a look,
   //The List we will return here will only have org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   
   //This is mainly to return the appropriate advisor from the candidate advisors according to the bean object we passed in. Let's go in and have a look
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}
	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
            //The BeanFactoryTransactionAttributeSourceAdvisor we have passed in is not the implementation of the IntroductionAdvisor interface and will not come here
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
            //The real use is here. Let's continue to jump in and have a look
            //If canApply returns true, it means that the current candidate can act on the current clazz, so it needs to be added to the list. It needs to be added when generating aop proxy later
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}
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 mainly obtains Pointcut through getPointcut and looks for classes and methods that should be aop enhanced from the target class
      PointcutAdvisor pca = (PointcutAdvisor) advisor;
      //We will go here. Let's continue to look. Here is to find the transaction properties of the corresponding class (simply get the @ Transactional related properties on the method). If we can get it here, we will return true, and if we can't get it, we will return false 
      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");
        
        //This is mainly to judge whether the class needs pointcut matching.
        //1. If the classes are TransactionalProxy, TransactionManager and PersistenceExceptionTranslator, there is no need for subsequent matching, and they will be returned directly from the if branch
        //2. Either the class you are looking for starts with java. Or the org.springframework.core interface also returns from here  
        //What we are looking for is the annotation of the transaction. The name is org.springframework.transaction.annotation.Transactional
        //The current class we want to match is com.springboot.transaction.service.impl.UserServiceImpl
        //The above two conditions do not match, so we will not enter this branch and continue to go down
		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 instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
            //We will go here and add com.springboot.transaction.service.impl.UserServiceImpl to the classes
			classes.add(ClassUtils.getUserClass(targetClass));
		}
        //The interface com.springboot.transaction.service.UserService implemented by the current class will also be added here
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		
        //In the following, we will traverse all the methods on the class to find out whether there is @ Transactional annotation
		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    	//We will go to the matching condition below. Let's go to this method to have a look
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}
//This method is in TransactionAttributeSourcePointcut, which is an abstract class
//Currently, this class is an internal anonymous class in BeanFactoryTransactionAttributeSourceAdvisor, and the class instance object name is pointcut
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
        //This tas is the bean of TransactionAttributeSource injected when initializing BeanFactoryTransactionAttributeSourceAdvisor
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}
//This method is in AbstractFallbackTransactionAttributeSource,
//The actual type of the bean injected into the TransactionAttributeSource is AnnotationTransactionAttributeSource, which inherits AbstractFallbackTransactionAttributeSource
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }

   // First, see if we have a cached value.
    //A cached key will be generated here
   Object cacheKey = getCacheKey(method, targetClass);
   //Check whether the corresponding transaction attribute exists from the cache. If it exists, it will be returned directly. This is the first time, and we will go to the later acquisition part
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      else {
         return cached;
      }
   }
   else {
      // We need to work it out.
      //This is to check whether there is a corresponding Transactional annotation on the corresponding method. If so, it will be encapsulated into a TransactionAttribute and returned
      //This is also done through the SpringTransactionAnnotationParser.parseTransactionAnnotation method. This is relatively simple and will not be included
      TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
      // Put it in the cache.
      if (txAttr == null) {
         //If it is not available, a cache will also be added here to avoid subsequent repeated lookups 
         this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
      }
      else {
         //At present, we will come here. methodIdentification is the splicing of class name and method name as a description
         String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
         if (txAttr instanceof DefaultTransactionAttribute) {
            DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
            dta.setDescriptor(methodIdentification);
            dta.resolveAttributeStrings(this.embeddedValueResolver);
         }
         if (logger.isTraceEnabled()) {
            logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
         }
         //Here, the resolved TransactionAttribute is added to the cache and returned
         this.attributeCache.put(cacheKey, txAttr);
      }
      return txAttr;
   }
}

If the above transaction attribute TransactionAttribute is not empty, it means that the current class can be used to generate aop agents for enhanced transaction processing. Will call

Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

To generate the corresponding agent class for transaction processing.

5. Generate corresponding proxy class

Let's go to the createProxy method to see the generation process of the proxy class

//This method is in AbstractAutoProxyCreator
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);
		}
		//This is a proxy class project. The following is mainly to set some properties. proxyFactory.getProxy(classLoader) will be set in the last line of the method; Generate proxy objects. Let's go in and have a look
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

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

		// Use original ClassLoader if bean class not locally loaded in overriding class loader
		ClassLoader classLoader = getProxyClassLoader();
		if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
			classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
		}
		return proxyFactory.getProxy(classLoader);
	}
	public Object getProxy(@Nullable ClassLoader classLoader) {
        //First create the proxy class of the corresponding class, and then use the proxy class to generate the proxy object
		return createAopProxy().getProxy(classLoader);
	}

	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		//In this case, the actual factory DefaultAopProxyFactory will be called to generate the proxy class
		return getAopProxyFactory().createAopProxy(this);
	}

	//This method is in DefaultAopProxyFactory
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(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 it is an interface or a proxy class, it will be the dynamic proxy of java
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
            //The others will come here
            //Our current is com.springboot.transaction.service.impl.UserServiceImpl, which will come here
            //Here, the proxy class is generated, and this will be used to generate the proxy object we need
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
//This method is in CglibAopProxy, and the specific generated proxy class will also be here
	@Override
	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 (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
				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 is used to create proxy classes, which is similar to Configuration. I won't look at some details
            //The specific approach is to set properties on enhancer, finally call asm, dynamically generate bytecode, load it into the jvm, generate a new proxy class object, and create a proxy class object
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
                //The classLoader is set here, which is required when the generated class is finally loaded into the jvm
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
            //Here, set the parent class com.springboot.transaction.service.impl.UserServiceImpl of the final generated proxy class
			enhancer.setSuperclass(proxySuperClass);
            //This is to set the interface to be implemented by the final generated proxy class (SpringProxy.class,Advised.class). We will take a look at this method later
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            //This is the generation policy for setting the proxy class name
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            //This is to set the generation strategy of the proxy class, that is, the bytecode generation strategy. The final bytecode generation will be completed by this class (call its generate method)
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
			
            //Here is the interceptor to be used in the setup agent
			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
            //Here is the setting to select different interceptors according to different methods of our target class, call accept according to different methods, return a subscript corresponding to the above callbacks array, and select different interceptors for processing
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
            //Finally, the proxy target class will be generated here and the object will be created
            //It should be noted here that enhancer has a property useFactory, which is true by default. At this time, the proxy class we finally generate will also implement the org.springframework.cglib.proxy.Factory interface in addition to the two interfaces of springproxy and advised
            //After the object is created using the construction method, it will call ((Factory) proxyInstance).setCallbacks(callbacks) to inject the interceptor we created above into the object
			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);
		}
	}

Let's take a look at the method AopProxyUtils.completeProxiedInterfaces(this.advised), which is the static method of AopProxyUtils

	public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) {
        //Go on in
		return completeProxiedInterfaces(advised, false);
	}
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
    //The advised object here is the ProxyFactory object created earlier. The interface to be proxied has not been added before. The specifiedInterfaces returns an empty array
		Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
		if (specifiedInterfaces.length == 0) {
			// No user-specified interfaces: check whether target class is an interface.
            //targetClass is com.springboot.transaction.service.impl.UserServiceImpl
			Class<?> targetClass = advised.getTargetClass();
			if (targetClass != null) {
				if (targetClass.isInterface()) {
					advised.setInterfaces(targetClass);
				}
				else if (Proxy.isProxyClass(targetClass)) {
					advised.setInterfaces(targetClass.getInterfaces());
				}
				specifiedInterfaces = advised.getProxiedInterfaces();
			}
		}
    	//This sentence is to judge whether the interface in the advertised is a subclass or sub interface of SpringProxy. Currently, the advertised does not contain the interface, so this is not included. Note that it is reversed here. This addSpringProxy is false
		boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    	
    	//The attribute isOpaque() is used to determine whether AOP agents should be prevented from being converted to Advised. The default value is "false", which means that any AOP agent can be converted to Advised. Currently, this is also false
    	//The second condition is to judge whether the interface of the current advertised is a subclass or sub interface of advised. The current advertised does not contain the interface, so this is not included. Note that it is reversed here, and this addAdvised is true   
		boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    
    	//The decoratingProxy passed from the upper layer is false
		boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
		int nonUserIfcCount = 0;
		if (addSpringProxy) {
			nonUserIfcCount++;
		}
		if (addAdvised) {
			nonUserIfcCount++;
		}
		if (addDecoratingProxy) {
			nonUserIfcCount++;
		}
    	
    	//The following is to set the array size of the interface to be implemented by the target proxy class according to the above judgment value, and then add the interface.
    	//We will add two interfaces, springproxy. Class and advised. Class
		Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
		System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
		int index = specifiedInterfaces.length;
		if (addSpringProxy) {
			proxiedInterfaces[index] = SpringProxy.class;
			index++;
		}
		if (addAdvised) {
			proxiedInterfaces[index] = Advised.class;
			index++;
		}
		if (addDecoratingProxy) {
			proxiedInterfaces[index] = DecoratingProxy.class;
		}
		return proxiedInterfaces;
	}

Let's look at the getCallbacks method here, which is in CglibAopProxy

	private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
		// Parameters used for optimization choices...
        
		boolean exposeProxy = this.advised.isExposeProxy();  //false
		boolean isFrozen = this.advised.isFrozen();			 //false
		boolean isStatic = this.advised.getTargetSource().isStatic();   //true

		// Choose an "aop" interceptor (used for AOP calls).
        //A dynamic advised interceptor will be created here, and the final transaction agent is actually completed through this class
		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 ?
                    //The staticunadvisesexposedinterceptor returned here is mainly used for static methods that do not require agent enhancement. The internal implementation is to call methods directly through reflection without other processing           
					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 ?
                //The StaticDispatcher returned here is relatively simple. It can quickly return the original class. Here is com.springboot.transaction.service.impl.UserServiceImpl                               
				new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

        //Here, all interceptors will be encapsulated into the callback array, and different interceptors will be used for different methods in the final generated bytecode.
		Callback[] mainCallbacks = new 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 = CollectionUtils.newHashMap(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(method, 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;
	}

6. Decompile the final generated proxy class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.springboot.transaction.service.impl;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Dispatcher;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;

public class UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052 extends UserServiceImpl implements SpringProxy, Advised, Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private MethodInterceptor CGLIB$CALLBACK_1;
    private NoOp CGLIB$CALLBACK_2;
    private Dispatcher CGLIB$CALLBACK_3;
    private Dispatcher CGLIB$CALLBACK_4;
    private MethodInterceptor CGLIB$CALLBACK_5;
    private MethodInterceptor CGLIB$CALLBACK_6;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$findAll$0$Method;
    private static final MethodProxy CGLIB$findAll$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK9() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.springboot.transaction.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        CGLIB$findAll$0$Method = ReflectUtils.findMethods(new String[]{"findAll", "(Ljava/util/Map;)Ljava/util/List;"}, (var1 = Class.forName("com.springboot.transaction.service.impl.UserServiceImpl")).getDeclaredMethods())[0];
        CGLIB$findAll$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/util/Map;)Ljava/util/List;", "findAll", "CGLIB$findAll$0");
    }

    final List CGLIB$findAll$0(Map var1) {
        return super.findAll(var1);
    }

    public final List findAll(Map var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (List)var10000.intercept(this, CGLIB$findAll$0$Method, new Object[]{var1}, CGLIB$findAll$0$Proxy) : super.findAll(var1);
    }

    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_5;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_5;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$2() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_6;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_6;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 211025071:
            if (var10000.equals("findAll(Ljava/util/Map;)Ljava/util/List;")) {
                return CGLIB$findAll$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }

        return null;
    }

    public final int indexOf(Advisor var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).indexOf(var1);
    }

    public final int indexOf(Advice var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).indexOf(var1);
    }

    public final boolean isFrozen() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).isFrozen();
    }

    public final boolean isInterfaceProxied(Class var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).isInterfaceProxied(var1);
    }

    public final TargetSource getTargetSource() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).getTargetSource();
    }

    public final int getAdvisorCount() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).getAdvisorCount();
    }

    public final boolean isProxyTargetClass() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).isProxyTargetClass();
    }

    public final void setTargetSource(TargetSource var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).setTargetSource(var1);
    }

    public final void setExposeProxy(boolean var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).setExposeProxy(var1);
    }

    public final Advisor[] getAdvisors() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).getAdvisors();
    }

    public final void addAdvisor(Advisor var1) throws AopConfigException {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).addAdvisor(var1);
    }

    public final void addAdvisor(int var1, Advisor var2) throws AopConfigException {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).addAdvisor(var1, var2);
    }

    public final boolean replaceAdvisor(Advisor var1, Advisor var2) throws AopConfigException {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).replaceAdvisor(var1, var2);
    }

    public final boolean isExposeProxy() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).isExposeProxy();
    }

    public final boolean isPreFiltered() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).isPreFiltered();
    }

    public final void setPreFiltered(boolean var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).setPreFiltered(var1);
    }

    public final boolean removeAdvice(Advice var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).removeAdvice(var1);
    }

    public final boolean removeAdvisor(Advisor var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).removeAdvisor(var1);
    }

    public final void removeAdvisor(int var1) throws AopConfigException {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).removeAdvisor(var1);
    }

    public final void addAdvice(Advice var1) throws AopConfigException {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).addAdvice(var1);
    }

    public final void addAdvice(int var1, Advice var2) throws AopConfigException {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        ((Advised)var10000.loadObject()).addAdvice(var1, var2);
    }

    public final Class[] getProxiedInterfaces() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).getProxiedInterfaces();
    }

    public final String toProxyConfigString() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((Advised)var10000.loadObject()).toProxyConfigString();
    }

    public final Class getTargetClass() {
        Dispatcher var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return ((TargetClassAware)var10000.loadObject()).getTargetClass();
    }

    public UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052 var1 = (UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            Callback[] var10001 = (Callback[])var10000;
            var1.CGLIB$CALLBACK_6 = (MethodInterceptor)((Callback[])var10000)[6];
            var1.CGLIB$CALLBACK_5 = (MethodInterceptor)var10001[5];
            var1.CGLIB$CALLBACK_4 = (Dispatcher)var10001[4];
            var1.CGLIB$CALLBACK_3 = (Dispatcher)var10001[3];
            var1.CGLIB$CALLBACK_2 = (NoOp)var10001[2];
            var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052 var10000 = new UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        throw new IllegalStateException("More than one callback object required");
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052 var10000 = new UserServiceImpl$$EnhancerBySpringCGLIB$$fb4ce052;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        Object var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        case 1:
            var10000 = this.CGLIB$CALLBACK_1;
            break;
        case 2:
            var10000 = this.CGLIB$CALLBACK_2;
            break;
        case 3:
            var10000 = this.CGLIB$CALLBACK_3;
            break;
        case 4:
            var10000 = this.CGLIB$CALLBACK_4;
            break;
        case 5:
            var10000 = this.CGLIB$CALLBACK_5;
            break;
        case 6:
            var10000 = this.CGLIB$CALLBACK_6;
            break;
        default:
            var10000 = null;
        }

        return (Callback)var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            break;
        case 1:
            this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;
            break;
        case 2:
            this.CGLIB$CALLBACK_2 = (NoOp)var2;
            break;
        case 3:
            this.CGLIB$CALLBACK_3 = (Dispatcher)var2;
            break;
        case 4:
            this.CGLIB$CALLBACK_4 = (Dispatcher)var2;
            break;
        case 5:
            this.CGLIB$CALLBACK_5 = (MethodInterceptor)var2;
            break;
        case 6:
            this.CGLIB$CALLBACK_6 = (MethodInterceptor)var2;
        }

    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2, this.CGLIB$CALLBACK_3, this.CGLIB$CALLBACK_4, this.CGLIB$CALLBACK_5, this.CGLIB$CALLBACK_6};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];
        this.CGLIB$CALLBACK_2 = (NoOp)var1[2];
        this.CGLIB$CALLBACK_3 = (Dispatcher)var1[3];
        this.CGLIB$CALLBACK_4 = (Dispatcher)var1[4];
        this.CGLIB$CALLBACK_5 = (MethodInterceptor)var1[5];
        this.CGLIB$CALLBACK_6 = (MethodInterceptor)var1[6];
    }

    static {
        CGLIB$STATICHOOK9();
    }
}

Keywords: Java Distribution

Added by evildarren on Fri, 26 Nov 2021 15:48:23 +0200