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组件

spring通过注解注册bean的方式+spring生命周期的更多相关文章

  1. @Scope注解设置创建bean的方式和生命周期

    1.1.1            Scope注解创建bean的方式和生命周期 作用 Scope设置对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式. 取 ...

  2. Spring框架系列(三)--Bean的作用域和生命周期

    Bean的作用域 Spring应用中,对象实例都是在Container中,负责创建.装配.配置和管理生命周期(new到finalize()) Spring Container分为两种: 1.BeanF ...

  3. 五 Spring的配置:Bean的配置,生命周期和作用范围

    Bean相关的配置: <bean>标签的id和name的配置: id:使用了约束中的唯一约束,里面不能出现特殊字符 name:没有使用唯一约束,理论上可以重复,实际上开发不行,里面可以出现 ...

  4. 【String注解驱动开发】面试官让我说说:如何使用FactoryBean向Spring容器中注册bean?

    写在前面 在前面的文章中,我们知道可以通过多种方式向Spring容器中注册bean.可以使用@Configuration结合@Bean向Spring容器中注册bean:可以按照条件向Spring容器中 ...

  5. 【String注解驱动开发】如何按照条件向Spring容器中注册bean?这次我懂了!!

    写在前面 当bean是单实例,并且没有设置懒加载时,Spring容器启动时,就会实例化bean,并将bean注册到IOC容器中,以后每次从IOC容器中获取bean时,直接返回IOC容器中的bean,不 ...

  6. spring IOC容器实例化Bean的方式与RequestContextListener应用

    spring IOC容器实例化Bean的方式有: singleton 在spring IOC容器中仅存在一个Bean实例,Bean以单实例的方式存在. prototype 每次从容器中调用Bean时, ...

  7. 在Listener(监听器)定时启动的TimerTask(定时任务)中使用Spring@Service注解的bean

    1.有时候在项目中需要定时启动某个任务,对于这个需求,基于JavaEE规范,我们可以使用Listener与TimerTask来实现,代码如下: public class TestTaskListene ...

  8. Spring中Bean的作用域、生命周期

                                   Bean的作用域.生命周期 Bean的作用域 Spring 3中为Bean定义了5中作用域,分别为singleton(单例).protot ...

  9. Spring之Bean的作用域与生命周期

    在前面博客中提到容器启动获得BeanDefinition对象中有一个scope 属性.该属性控制着bean对象的作用域.本章节介绍Bean的作用域及生命周期,了解bean是怎么来的又怎么没的. 一.B ...

随机推荐

  1. 什么是Sprint计划?

    Sprint 计划是Scrum框架中的一个事件,团队将确定他们将在冲刺期间处理的产品积压项目,并讨论他们完成这些产品积压项目的初始计划. 团队可能会发现建立冲刺目标很有帮助,并以此为基础确定他们在冲刺 ...

  2. Linux C语言链表详细分析

    链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用.链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节 ...

  3. Python小练习之验证“哥德巴赫猜想”

    设计内容:任何一个大于2的偶数都可以分解为两个素数之和,这就是著名的哥达巴赫猜想. 设计要求:要求输入一个大于2的偶数,程序运行后,输出两个素数,其和正好等于该偶数. 1.    实验代码(知道是你们 ...

  4. c++ 算法 next_permutation

    遇到这个算法是在大牛写的10行的8皇后问题中,下面首先给出这个10行就解决了8皇后的NB代码,我目前还是没有看懂对于皇后不在同一列的判断,因为他巧妙的用了移位操作. #include<iostr ...

  5. pip 常用命令小结

    pip 常用命令小结 pip这个工具我们经常会用到,毕竟python 是一门以第三方库庞大而著名的编程语言,所以我们总会用pip 安装一些依赖库,当然这只是pip 最常用的一个命令,下面就来介绍一下 ...

  6. mysql-5.7.30安装

    1.由于在线安装受制于网络环境,所以选择tar包编译安装.      首先去mysql镜像站下载mysql-5.7.30-linux-glibc2.5-x86_64.tar.gz2.上传到linux服 ...

  7. C# 合并两个数组总结

    byte[] b1 = new byte[] { 1, 2, 3, 4, 5 }; byte[] b2 = new byte[] { 6, 7, 8, 9 }; byte[] b3 = new byt ...

  8. 12组-Alpha冲刺-3/6

    一.基本情况 队名:字节不跳动 组长博客:https://www.cnblogs.com/147258369k/p/15546442.html 小组人数:10人 二.冲刺概况汇报 侯钦凯 过去两天完成 ...

  9. JS中innerHTML、outerHTML、innerText 、outerText、value的区别与联系?

    1.innerHTML 属性 (参考自<JavaScript高级程序设计>294页) 在读模式下,innerHTML 属性返回与调用元素的所有子节点(包括元素.注释和文本节点)对应的 HT ...

  10. Python 数据类型常用的内置方法(一)

    目录 Python 数据类型常用的内置方法 1.整型 int 2.浮点型 float 字符串转浮点型: 3.字符串 str 多种类型转字符型: 索引 切片 len( )方法:统计字符串长度/个数 移除 ...