spring通过注解注册bean的方式+spring生命周期

spring容器通过注解注册bean的方式

  1. @ComponentScan + 组件标注注解 (@Component/@Service...)
    @ComponentScan(value = "com.example.demo.annotation")
    
    spring会将com.example.demo.annotation目录下标注了spring能识别的注解的类注册为bean
    @ComponentScan 还可以指定排除和包含规则
    • excludeFilters: 指定排除规则,排除哪些组件
    • includeFilters: 指定只需要包含哪些组件,需要设置 useDefaultFilters = false
    • FilterType.ANNOTATION 基于注解过滤
    • FilterType.ASSIGNABLE_TYPE : 基于给定的类型过滤
    • ...
    • FilterType.CUSTOM: 自定义规则过滤
    @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
    )
    
    其中CUSTOM自定义规则中的MyTypeFilter需要实现TypeFilter接口,举例如下
    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 (可以将第三方包中的类注册为bean)
    @Bean
    Person person() {
        return new Person("zhang");
    }
    
  3. @Import
    @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    
    • 导入一个普通类,容器会自动注册这个组件,组件的id默认是类的全类名
    • 导入ImportSelector :返回需要注册的组件
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{"com.example.demo.annotation.bean.Red"};
        }
    }
    
    • 导入ImportBeanDefinitionRegistrar
    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. 使用spring提供的 FactoryBean
    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") 默认获取到的是FactoryBean调用getObject方法返回的对象
    要获取FactoryBean本身,需要在id前面加个& (&colorFactoryBean)

当满足某种条件时才注册bean,使用@Conditional

举例:在windows和linux上分别注册不同的bean

    @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");
        }
    }

bean的生命周期

spring容器管理bean的生命周期:创建--》初始化--》销毁

我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期时来调用我们自定义的初始化和销毁方法

  1. 创建对象:
    单实例:在容器启动时创建对象
    多实例:在每次获取bean的时候创建对象

    每个BeanPostProcessor的 postProcessBeforeInitialization 方法会在初始化之前执行

  2. 初始化: 对象创建好,调用初始化方法
    每个BeanPostProcessor的 postProcessAfterInitialization 方法会在初始化之后执行

  3. 销毁:
    单实例:容器关闭时销毁
    多实例:容器会帮助创建这个bean,但不会管理这个bean,所以容器不会调用销毁方法,可以手动调用销毁方法

指定初始化和销毁的方法:

  1. 在 @Bean注解指定(initMethod = "",destroyMethod = "")
  2. 通过让bean实现 InitializingBean(定义初始化逻辑) 和 DisposableBean(定义销毁时逻辑)
  3. 使用JSR250: @PostConstruct (定义初始化逻辑) @PreDestroy(在容器销毁bean之前通知进行清理工作)

bean的后置处理器 BeanPostProcessor,其有如下两个方法,在bean的初始化前后做一些处理:

  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterInitialization:在初始化之后工作
@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;
    }
}

如果自定义组件想要使用spring容器底层的组件(ApplicationContext,BeanFactory,***),自定义组件可以实现 ***Aware,
在创建bean的时候,相关BeanPostProcessor会调用接口规定的方法注入相关组件

例如:

如果自定义bean 实现了ApplicationContextAware 接口,在ApplicationContextAwareProcessor中会调用ApplicationContextAware的
setApplicationContext方法,注入ApplicationContext组件

posted @ 2021-12-02 22:52  她的开呀  阅读(440)  评论(0编辑  收藏  举报