The principle of AOP as like as two peas and Mybatis integration into Spring are exactly the same principle. Before reading this article, I suggest reading the last one first.
Spring source code series (8) -- how Mybatis is integrated into spring source code analysis
https://blog.csdn.net/zxd1435513775/article/details/121180974
1, Spring startup process reanalysis
Configure the class and open the annotation @ EnableAspectJAutoProxy of AOP
@Configuration @ComponentScan("com.scorpios") @EnableAspectJAutoProxy public class AppConfig { }
Section class
@Aspect @Component public class AspectJScorpios { @Pointcut("execution(* com.scorpios.service..*.*(..))") public void pointCut(){ } @Before("pointCut()") public void before(){ System.out.println(" proxy before ... "); } }
Startup class
public static void main( String[] args ) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(AppConfig.class); ac.refresh(); XService xService = (XService) ac.getBean("XService"); xService.print(); }
1. Handle the Import process
For the processing of Import, you can take a look at chapter 4 of source code analysis, processing @ Import annotation in package scanning.
Spring source code series (IV) -- function analysis of configuration class postprocessor
https://blog.csdn.net/zxd1435513775/article/details/120935494
@The EnableAspectJAutoProxy annotation source code uses the @ Import annotation to Import the aspectjautoproxyregister class into the Spring container, and the aspectjautoproxyregister class implements the ImportBeanDefinitionRegistrar interface.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false; }
For an introduction to the @ Import annotation Import ImportBeanDefinitionRegistrar implementation class, see the Spring source code series (8),
The principle of AOP is the same as that of Mybatis by implementing the ImportBeanDefinitionRegistrar interface. The implementation class of Mybatis is mappercannerregister, and the implementation class of AOP is aspectjautoproxyregister.
// Mybatis
class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar
// AOP
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar
2. Execute Import class
In parser.parse(candidates); In this line of code, the @ Import annotation is imported, the class implementing the ImportBeanDefinitionRegistrar interface is instantiated, and the created real column is placed in the property importBeanDefinitionRegistrars of the ConfigurationClass class. You can see the following broken point diagram.
this.reader.loadBeanDefinitions() method completes the call to the ImportBeanDefinitionRegistrar interface method.
Let's take a look at the methods that implement the ImportBeanDefinitionRegistrar interface in the aspectjautoproxyregister class. The entrance of AOP is right here!!!!
2, AOP source code analysis
1. Aspectjautoproxyregister class
Take a look at the ImportBeanDefinitionRegistrar interface method implemented in the aspectjautoproxyregister class.
The function of this method is to add a BeanDefinition to the Spring container. The beanName is org.springframework.aop.config.internalAutoProxyCreator. beanClass is AnnotationAwareAspectJAutoProxyCreator.class.
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // Core method 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); } } } }
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) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // The bean class here is AnnotationAwareAspectJAutoProxyCreator.class RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // Register a BeanDefinition with beanName org.springframework.aop.config.internalAutoProxyCreator in beanDefinitionMap registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
2. internalAutoProxyCreator class
Take another look at internalAutoProxyCreator. Its implementation class is org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
After the registerbanpostprocessors () method in the refresh() method, the BeanPostProcessor has been instantiated and added to the beanPostProcessors property in the beanFactory factory.
3. BeanPostProcessor method execution
Let's take a look at the execution time of the BeanPostProcessor. In the initializeBean() method after the assignment of the populateBean() attribute, we call the Bean post processor method.
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // Permission check if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // Perform setBeanName/setBeanFactory assignment invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // Call the postProcessBeforeInitialization() method in the BeanPostProcessor interface wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // Execute the custom init method method invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { // Throw exception code omitted } if (mbd == null || !mbd.isSynthetic()) { // Call the postProcessAfterInitialization() method in the BeanPostProcessor interface // The AOP proxy is in this method of the AnnotationAwareAspectJAutoProxyCreator class // The parent class AbstractAutoProxyCreator of AnnotationAwareAspectJAutoProxyCreator implements this method wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
After the postProcessAfterInitialization() method in the AnnotationAwareAspectJAutoProxyCreator class above is executed, the XService instance becomes a Cglib proxy object.
Let's analyze the source code:
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
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; } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // Create proxy object 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; }
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); } 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); } return proxyFactory.getProxy(getProxyClassLoader()); } public Object getProxy(@Nullable ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); } public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // This judgment is very important. It can be configured through the configuration file to determine what dynamic agent to use if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { // Throwing anomaly } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { // Create JDK dynamic proxy return new JdkDynamicAopProxy(config); } // Create Cglib dynamic proxy return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
3, Summary
The principle of AOP is the same as that of Mybatis. It uses the @ Import import ImportBeanDefinitionRegistrar extension point in Spring. First add a BeanDefinition to the container, and then call the method at the appropriate time.
The two articles can be compared.