Spring registers bean s through annotations + spring lifecycle

The spring container registers bean s through annotations

  1. @ComponentScan + Component annotation (@ Component/@Service...)
    @ComponentScan(value = "com.example.demo.annotation")
    
    Spring will register the classes marked with annotations recognized by spring in the com.example.demo.annotation directory as bean s
    @ComponentScan can also specify exclusion and inclusion rules
    • excludeFilters: specify exclusion rules and which components to exclude
    • includeFilters: specify which components only need to be included. useDefaultFilters = false should be set
    • FilterType.ANNOTATION filtering based on annotations
    • FilterType.ASSIGNABLE_TYPE: filter based on the given type
    • ...
    • FilterType.CUSTOM: custom filtering rules
    @ComponentScan(value = "com.example.demo.annotation",
            /*excludeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
            },*/
            includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Configuration.class}),
                    @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {TestController.class}),
                    @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
            },useDefaultFilters = false
    )
    
    MyTypeFilter in CUSTOM custom rule needs to implement TypeFilter interface, for example:
    public class MyTypeFilter implements TypeFilter {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            String className = metadataReader.getClassMetadata().getClassName();
            System.out.println("------>"+className);
            if (className.contains("er")){
                return true;
            }
            return false;
        }
    }
    
  2. @Bean (classes in third-party packages can be registered as beans)
    @Bean
    Person person() {
        return new Person("zhang");
    }
    
  3. @Import
    @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    
    • When you import a common class, the container will automatically register the component. The component id is the full class name of the class by default
    • Import ImportSelector: returns the components that need to be registered
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{"com.example.demo.annotation.bean.Red"};
        }
    }
    
    • Import ImportBeanDefinitionRegistrar class
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            boolean b = registry.containsBeanDefinition("com.example.demo.annotation.bean.Color");
            boolean b1 = registry.containsBeanDefinition("com.example.demo.annotation.bean.Red");
            if (b && b1){
                registry.registerBeanDefinition("rainBow",new RootBeanDefinition(RainBow.class));
            }
        }
    }
    
  4. Use the FactoryBean provided by spring
    public class ColorFactoryBean implements FactoryBean<Color> {
        @Override
        public Color getObject() throws Exception {
            return new Color();
        }
    
        @Override
        public Class<?> getObjectType() {
            return Color.class;
        }
    }
    
    @Bean
    ColorFactoryBean colorFactoryBean() {
        return new ColorFactoryBean();
    }
    
    applicationContext.getBean("colorFactoryBean") obtains the object returned by the FactoryBean calling the getObject method by default
    To get the FactoryBean itself, you need to add & (& colorfactorybean) before the id

Register bean s only when certain conditions are met, using @ Conditional

Example: register different bean s on windows and linux respectively

    @Conditional({WindowsConditional.class})
    @Bean("windows")
    Person person1() {
        return new Person("windows");
    }

    @Bean("linux")
    @Conditional({LinuxConditional.class})
    Person person2() {
        return new Person("linux");
    }

    public class WindowsConditional implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            Environment environment = conditionContext.getEnvironment();
            String property = environment.getProperty("os.name");
            return property.toLowerCase().contains("windows");
        }
    }

    public class LinuxConditional implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            Environment environment = conditionContext.getEnvironment();
            String property = environment.getProperty("os.name");
            return property.toLowerCase().contains("linux");
        }
    }

The lifecycle of a bean

The life cycle of spring container managed bean s: create -- initialize -- destroy

We can customize the initialization and destruction methods, and the container will call our customized initialization and destruction methods when the bean reaches the current life cycle

  1. Create object:
    Single instance: creates an object when the container starts
    Multi instance: create an object every time you get a bean

    The postProcessBeforeInitialization method of each BeanPostProcessor is executed before initialization

  2. Initialization: after the object is created, call the initialization method
    The postProcessAfterInitialization method of each BeanPostProcessor is executed after initialization

  3. Destruction:
    Single instance: destroy when container is closed
    Multi instance: the container will help create this bean, but it will not manage this bean, so the container will not call the destruction method, and you can call the destruction method manually

Specify the method of initialization and destruction:

  1. Specify in @ Bean annotation (initmethod = '', destroymethod = '')
  2. By letting the bean implement InitializingBean (defining initialization logic) and DisposableBean (defining destruction logic)
  3. Use JSR250: @PostConstruct (define initialization logic) @ PreDestroy (notify the container to clean up before destroying bean s)

The bean post processor, BeanPostProcessor, has the following two methods to do some processing before and after bean initialization:

  • postProcessBeforeInitialization: works before initialization
  • postProcessAfterInitialization: works after initialization
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    private final ApplicationContext applicationContext;

    public MyBeanPostProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization--->"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization--->"+beanName);
        return bean;
    }
}

If the custom component wants to use the components at the bottom of the spring container (ApplicationContext, BeanFactory, * * *), the custom component can implement * * * Aware,
When creating a bean, the relevant BeanPostProcessor will call the methods specified in the interface to inject relevant components

For example:

If the custom bean implements the ApplicationContextAware interface, the ApplicationContextAware interface will be called in the ApplicationContextAware processor
setApplicationContext method, inject ApplicationContext component

Posted on Thu, 02 Dec 2021 14:01:08 -0500 by baruch