写了两年代码之后再来谈一谈Spring中的Bean

编辑: admin 分类: java 发布时间: 2021-12-03 来源:互联网
目录
  • (一)什么是Bean
  • (二)如何往Spring容器中添加Bean
  • (三)Bean的作用域
  • (四)Bean的常用注解
    • 4.1 Conditional
    • 4.2 ComponentScan
    • 4.3 @Import
  • (五)Bean的初始化和销毁
    • 1、自定义初始化方法和销毁方法
    • 2、通过 InitializingBean, DisposableBean 接口实现
    • 3、BeanPostProcessor
  • (六)总结

    (一)什么是Bean

    Spring中的Bean简单来讲就是一个个被Spring容器管理的Java对象,我们写了一个类之后,这个类只是一个单纯的Java类,可以通过new的方式去创建它。当我们把这个类添加到Spring的容器里之后,这个类就变成了Bean,由Spring容器管理,可以通过自动注入的方式去使用。

    (二)如何往Spring容器中添加Bean

    这里列出四种常用的添加Bean的方式。

    1、@Bean: 写一个普通的类时最常用的添加Bean的方式

    2、@ComponentScan + @Controller @Service @Component @Repository:SpringBoot写多了之后一定会很熟悉这些。

    3、@Import:通过导入的方式注入Bean

    4、@ImportBeanDefinitionRegister:和Import类似,可以指定Bean的名称

    (三)Bean的作用域

    首先介绍最基本的@Bean注解,@Bean注解声明这个类是一个Bean,在Spring5之前,大部分的声明都会放到配置文件里,Spring5之后通过两个注解就可以完成。以Teacher类为例

    public class Teacher {
    }
    
    @Configuration
    public class MainConfig {
        @Bean
        public Teacher teacher(){
            return new Teacher();
        }
    }
    

    在不指定@Scope的情况下,所有bean的实例都是单实例的bean,并且是饿汉式加载(容器启动时就创建好了)。可以通过注解@Lazy实现懒加载(在调用时被加载)。

    @Bean
    //@Lazy
    public User user(){
        return new User();
    }
    

    指定@Scope为prototype表示为多实例,并且是懒汉式加载(使用时才会创建)

    @Bean
    @Scope(value = "prototype")
    public User user(){
        return new User();
    }
    

    列出其他的几种Bean作用域:

    singleton  单例(默认)
    prototype  多实例
    request  同一次请求
    session  同一个会话级别
    

    (四)Bean的常用注解

    有几个注解经常会和@Bean一起使用

    4.1 Conditional

    Conditional注解的意思是条件,即满足条件的情况下才会生效
    比如我在Bean中配置了Conditional:

    @Bean
    @Conditional(value = TeacherCondition.class)
    public Teacher teacher(){
        return new Teacher();
    }
    

    TeacherCondition 代码如下:如果Spring的Bean中有名字为student的,则返回true,否则返回false

    public class TeacherCondition implements Condition {
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            if (conditionContext.getBeanFactory().containsBean("student")){
                return true;
            }
            return false;
        }
    }
    

    最后的结果就是,如果TeacherCondition返回的是true,则teacher这个bean会被注册到容器中,否则就不会注册到容器中。

    4.2 ComponentScan

    这个注解会和Controller、Service等同时出现,给一个类添加Controller、Service等注解后,需要在配置类中增加ComponentScan,ComponentScan扫描到的包下的Controller、Service等注解才会生效:

    @Configuration
    //最基本的扫描路径方式
    //@ComponentScan(basePackages = {"com.javayz.testcompentscan"})
    //增加了Filter的方式
    @ComponentScan(basePackages = {"com.javayz.testcompentscan"},includeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class}),
            @ComponentScan.Filter(type = FilterType.CUSTOM,value = {TestFilterType.class})
    },useDefaultFilters = false)
    public class MainConfig {
    
        @Bean
        @Scope(value = "prototype")
        public User user(){
            return new User();
        }
    }
    

    Filter是在扫描时的过滤器,比如设置FilterType.ANNOTATION表示只有这里设置的注解才会被扫描到,FilterType.CUSTOM是自定义过滤器,TestFilterType 类进行了一层判断:包名为dao下的类会被注册到Bean容器中

    public class TestFilterType implements TypeFilter {
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            //获取当前类的class源信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            if (classMetadata.getClassName().contains("dao")){
                return true;
            }
            return false;
        }
    }
    

    4.3 @Import

    @Import可以用来往容器中导入第三方的组件,也可以起到和@Bean一样的作用:

    @Configuration
    //@Import(value = {Teacher.class, Student.class})
    //@Import(value = {MyImportSelector.class})
    @Import(value = {MyBeanDefinitionRegister.class})
    public class MainConfig {
    }
    

    第一种方式直接导入对应的类,这里和直接写@Bean效果一致

    @Import(value = {Teacher.class, Student.class})
    

    第二种方式导入ImportSelector对象,通过selectImports方法返回要导入Bean的全限定名:

    public class MyImportSelector implements ImportSelector {
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{"com.javayz.testimport.compent.Teacher"};
        }
    }
    

    第三种方式通过BeanDefinitionRegister注入Bean(可以指定Bean的名称)

    public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Student.class);
            registry.registerBeanDefinition("student",rootBeanDefinition);
        }
    }
    

    Import注解最常用的场景就是SpringBoot自动注入,在SpringBoot自动注入源码中导出可以看到@Import注解的身影。

    (五)Bean的初始化和销毁

    当由容器管理Bean的生命周期时,我们可以通过自己指定Bean方法的初始化方法和销毁方法,使得一个Bean在初始化和销毁时能执行自己的方法。

    1、自定义初始化方法和销毁方法

    public class Teacher {
        public Teacher(){
            System.out.println("Teacher 构造方法");
        }
        public void init(){
            System.out.println("Teacher 初始化方法");
        }
        public void destory(){
            System.out.println("Teacher 销毁方法");
        }
    }
    
    @Configuration
    public class MainConfig {
        @Bean(initMethod = "init",destroyMethod = "destory")
        public Teacher teacher(){
            return new Teacher();
        }
    }
    

    对于单例bean(singleton)容器启动的时候,bean对象就创建了,在容器销毁的时候,就会去调用Bean的销毁方法。

    对于多实例的bean,容器启动的时候bean还未被创建,在获取Bean的时候才会被创建,并且bean的销毁不受IOC容器的管理。

    2、通过 InitializingBean, DisposableBean 接口实现

    Spring的这两个接口也可以实现初始化和销毁的功能。

    public class Student implements InitializingBean, DisposableBean {
        public Student(){
            System.out.println("Student 构造方法");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println("Student销毁");
        }
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("Student初始化");
        }
    }
    @Configuration
    public class MainConfig {
        @Bean
        public Student student(){
            return new Student();
        }
    }
    

    3、BeanPostProcessor

    BeanPostProcessor在所有Bean的初始化前和初始化后都会被调用

    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Bean初始化前");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Bean初始化后");
            return bean;
        }
    }
    
    @ComponentScan
    @Configuration
    public class MainConfig {
        @Bean(initMethod = "init",destroyMethod = "destory")
        public Teacher teacher(){
            return new Teacher();
        }
        @Bean
        public Student student(){
            return new Student();
        }
    }
    

    (六)总结

    别看Bean这个概念听起来简单,里面的内容还真不少。Spring的核心之一IOC也就是对Bean进行管理。我是鱼仔,我们下期再见!

    到此这篇关于写了两年代码之后再来看看Spring中的Bean的文章就介绍到这了,更多相关Spring中的Bean内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!

    【本文由:http://www.yidunidc.com/mgzq.html复制请保留原URL】