Spring source code analysis the fifth bullet - what other effects does God level spring have?

Posted by heltr on Tue, 11 Jan 2022 03:50:03 +0100

From the initial simple handwritten article to the current source code analysis article, the whole spring MVC has been completed.
We can see that various callbacks, such as AOP and MVC, are processed through callbacks. This article will take a look at what other practical uses spring has besides being used as a framework.

First, let's take a look at the callback of the spring bean creation process again

createBeanInstance -> Constructor -> setter methods ->
BeanNameAware.setBeanName ->BeanClassLoaderAware.setBeanClassLoader -> BeanFactoryAware.setBeanFactory -> BeanPostProcessor.postProcessBeforeInitialization ->
InitializingBean.afterPropertiesSet -> BeanPostProcessor.postProcessAfterInitialization

1. Constructor: initializes the object through the construction method, class newInstance()

2. setter methods, attribute method assignment, and dependency injection. There is a detailed explanation of dependency injection before, so I won't say more

3. BeanNameAware.setBeanName

  • Get the beanName of the current implementation class and prepare the following code. When initializing the current class, the beanName will be called back to this method
@Component
public class TestBeanNameAware implements BeanNameAware {
    @Override
    public void setBeanName(String name) {
        System.out.println("#Obtain beanname of TestBeanNameAware implementation class: "+ name");
    }
}

4. BeanClassLoaderAware.setBeanClassLoader

  • Gets the ClassLoader of the currently loaded class
@Component
public class TestBeanClassLoaderAware implements BeanClassLoaderAware {
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("#Get the classloader of the currently loaded class: "+ classloader");
    }
}

5. BeanFactoryAware.setBeanFactory

  • Get all the bean s in the container. The common ApplicationContextAware also has the same function
@Component
public class TestBeanFactoryAware implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("#Get the container of the management bean: "+ beanFactory.getClass().getName());
        //
        Object nameAware = beanFactory.getBean("testBeanNameAware");
        System.out.println(nameAware);
    }
}

6. BeanPostProcessor.postProcessBeforeInitialization ,postProcessAfterInitialization

  • Callbacks before and after bean initialization can return inheritance classes or proxy classes before and after bean initialization. aop is a typical example
@Component
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//        System.out.println("before initialization:" + bean. Getclass() getName()+","+beanName);
        if(beanName.equals("com.example.demo.action.TestAction")){
            System.out.println("After initialization:"+bean.getClass().getName()+","+beanName);
            return new Test1Action();   //Set to implement class or inheritance class to dynamically modify bean initialization
        }
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//        System.out.println("after initialization:" + bean. Getclass() getName()+","+beanName);
        if(beanName.equals("com.example.demo.action.TestAction")){
            System.out.println("After initialization:"+bean.getClass().getName()+","+beanName);
        }
        return null;
    }
}

7. InitializingBean.afterPropertiesSet

  • Initial callback of the current class. Case: implementation of MVC
@Component
public class TestInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("#After initialization, the current class callback is completed, and the post callback is preceded by "");
    }
}

8. ApplicationContextAware obtains container context, which is commonly used. I won't elaborate

9. BeanDefinitionRegistryPostProcessor

  • Custom registered bean s or properties
@Component
public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    /**
     * Implement the custom bean and register it with BeanDefinitionRegistry
     * @param registry
     * @throws BeansException
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        //The TestAction does not have any loaded identifier. You can use this method to register mybatis with the container
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(TestAction.class);
     	registry.registerBeanDefinition(TestAction.class.getName(),builder.getBeanDefinition());
        System.out.println("Register custom bean:"+builder.getBeanDefinition().getBeanClass());
    }

    /**
     * It is mainly used to customize and modify the attribute values in the held bean s
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (String definitionName : beanFactory.getBeanDefinitionNames()) {
            if ("com.example.demo.action.TestAction".equals(definitionName)) {
                System.out.println("###beanName:" + definitionName);
                BeanDefinition definition = beanFactory.getBeanDefinition(definitionName);
                //Get the defined value of the bean and dynamically modify the value. setter method is required
                MutablePropertyValues pv = definition.getPropertyValues();
                pv.addPropertyValue("name", "Wang Er Ma Zi");
                System.out.println("###TestAction#name (reassign) ";
                break;
            }
        }
    }
}

10. FactoryBean.getObject(), getObjectType()

  • Class that implements FactoryBean. When the container initializes this class, it will call the current getObject() method
//You can also register the class yourself. This method will also be called when the class is initially registered
BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(TestFatoryBean.class);
registry.registerBeanDefinition("aaabbbccc",builder1.getBeanDefinition());
@Component
public class TestFatoryBean implements FactoryBean {
    /**
     * When initializing this class, the definition of testfactorybean has been replaced by testfactorybean 1
     * TestFactoryBean1 can be annotated in other classes directly
     * @return Returned object instance
     * @throws Exception
     */
    @Override
    public Object getObject() throws Exception {
        System.out.println("#Initialize testfactorybean getObject()");
        return new TestFactoryBean1();
    }
    
    /**
     * @return Object type returned
     */
    @Override
    public Class<?> getObjectType() {
        System.out.println("#Initialize testfactorybean getObjectType()");
        return TestFactoryBean1.class;
    }
}

11. AbstractApplicationContext

  • Mainly container related events
@Component
public class TestAbstractApplicationContext extends AbstractApplicationContext {
    @Override
    protected void refreshBeanFactory() throws BeansException, IllegalStateException {
        System.out.println("#Refresh container event "");
    }

    @Override
    protected void closeBeanFactory() {
        System.out.println("#Close container event "");
    }
    /**
     * Return the existing container 𞓜 custom container
     * @return
     * @throws IllegalStateException
     */
    @Override
    public ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException {
        return null;
    }
}

12. DeferredImportSelector extends ImportSelector

  • Customize the class to be imported, and pass in the class name list for automatic assembly
  • Other classes are required. The annotation @ Import(TestDeferredImportSelector.class) is used
    First usage:
public class TestDeferredImportSelector implements ImportSelector {
	//Directly implement the package name path of the incoming class
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("#Delay importing importingClassMetadata to be loaded "");
        return new String[]{TestImportAction.class.getName()};
    }
}

The second usage can be implemented in groups:

public class TestDeferredImportSelector implements DeferredImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return null;
    }

    /**
     * If grouping is implemented, priority is given to grouping, which is the implementation class of de grouping
     * @return Returns the class that implements grouping (DeferredImportSelector.Group)
     */
    @Override
    public Class<? extends Group> getImportGroup() {
        return Test123.class;
    }

    private static class Test123 implements DeferredImportSelector.Group{

        AnnotationMetadata annotationMetadata;

        @Override
        public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
            System.out.println("#Delay the introduction of the process to be loaded ");
            this.annotationMetadata = metadata;
            //Here, you can make groups according to the original data, so that each group can load different classes
        }

        @Override
        public Iterable<Entry> selectImports() {
            System.out.println("#Delay importing the selectImports to be loaded ");
            String[] strings = {TestImportAction.class.getName()};
            return Arrays.asList(strings).stream().
                    map((className) -> new Entry(this.annotationMetadata,className)).collect(Collectors.toList());
        }
    }
}   

At present, there are so many things that can be sorted out. There must be others who are not considerate. There is not much in-depth research here

That is the whole content of this chapter.

Previous: Spring source code analysis fourth bullet - MVC analysis
Next: The sixth bullet of SpringMvc source code analysis - handwritten high imitation version based on SpringMvc source code

The method of reading is in order and step by step, familiar reading and careful thinking

Topics: Java Spring Design Pattern source code