Bean组件的装配、XML文件引入、绑定配置文件


该文章是为了后边理解SpringBoot的自动配置原理
平时开发中经常用到@Autowired注解注入Bean,以及学习Spring框架(这里指的是微观上的Spring Framework)中提到的IOC控制反转中的容器工厂。使用SSM时候大家是通过bean标签或者@Component等注解进行注入相应的Bean的那么在当下SpringBoot场景下又该如何导入所需要的Bean组件呢?

Bean的装配方式

1. @Configuration

  • 作用:声明标注该注解的类是配置类,AnnotationConfigWebApplicationContext类会对该注解进行扫描,从而构建出该类中@Bean对应的Bean并添加到IOC容器中。
    注意:该配置类也是一个Bean组件,会加载到IOC容器中去。
  • 使用:
    分为两种模式,通过proxyBeanMethods属性的值来控制。默认为true,即Full模式
  1. Full模式:重量级模式。
    该模式适合Bean组件之间有依赖关系的情况,该情况下被依赖的Bean会保持一致性(即该Bean先从IOC中进行查找和使用)(每次获取该Bean,他里边的依赖的Bean始终保持同一个)。
    保证每个@Bean方法被调用多少次返回的组件都是单实例的

实践场景:快速创建一个SpringBoot项目。
两个自定义实体类,后续会用到。用户、账户。用户拥有账户。

//省略get、set、toString方法
//User用户类
public class User {
    private String name;
    private Account account;
	private String password;
    public User() {
    }
    public User(String name, String password) 											{ 
        this.name = name;
        this.password = password;
    }
}
//Account账户类
public class Account {
    private String name;
    private String password;

    public Account() {
    }
}

自定义配置类。

@Configuration
//@Configuration(proxyBeanMethods = true)两者等同
public class MyBeanConfig {
    @Bean
    public Account account(){
        return new Account("payCard1","123");
    }

    @Bean
    public User user(){
        User user = new User("zhangsan", "zs");
        user.setAccount(account());
        return user;
    }
}

启动类中进行测试

@SpringBootApplication
public class BootApp {
    public static void main(String[] args) {
        //1.return IOC container.
        ConfigurableApplicationContext run = SpringApplication.run(BootApp.class, args);
        //2.get User Bean and Account Bean ,observing whether Account is same
        User user = run.getBean("user", User.class);
        System.out.println(user);
        Account account = run.getBean("account", Account.class);
        System.out.println(account);
        //User{name='zhangsan', account=com.yh.redistemplateitem.pojo.Account@e0847a9, password='zs'}
        //com.yh.redistemplateitem.pojo.Account@e0847a9
//container start time is  3898 ms
//3. get MyBeanConfig Bean ,use it method to create object.observing whether object is same

        MyBeanConfig myBeanConfig = run.getBean(MyBeanConfig.class);
        Account account1 = myBeanConfig.account();
        Account account2 = myBeanConfig.account();
        System.out.println(account1==account2);
        //true
    }
}

结论:
发现User中的Account就是IOC容器中的Account对象。使用配置类本身的Bean对象执行方法创建的Account是同一个,取得还是IOC中的

  1. Lite模式:轻量级模式
    适合组件之间没有依赖关系的情况,该模式不会多出Full模式下的额外的判断和查找过程,会加速容器的启动速度。可用于调优。
    每个@Bean方法被调用多少次返回的组件都是新创建的
    实践场景:快速创建一个SpringBoot项目。

自定义配置类。

@Configuration(proxyBeanMethods = false)
public class MyBeanConfig {
    @Bean
    public Account account(){
        return new Account("payCard1","123");
    }

    @Bean
    public User user(){
        User user = new User("zhangsan", "zs");
        user.setAccount(account());
        return user;
    }
}

启动类中进行测试

@SpringBootApplication
public class BootApp {
    public static void main(String[] args) {
        //1.return IOC container.
        ConfigurableApplicationContext run = SpringApplication.run(BootApp.class, args);
        //2.get User Bean and Account Bean ,observing whether Account is same
        User user = run.getBean("user", User.class);
        System.out.println(user);//User{name='zhangsan', account=com.yh.redistemplateitem.pojo.Account@4348fa35, password='zs'}
        Account account = run.getBean("account", Account.class);
        System.out.println(account);//com.yh.redistemplateitem.pojo.Account@563843f1
  //container start time is  3854 ms
  //3. get MyBeanConfig Bean ,use it method to create object.observing whether object is same

        MyBeanConfig myBeanConfig = run.getBean(MyBeanConfig.class);
        Account account1 = myBeanConfig.account();
        Account account2 = myBeanConfig.account();
        System.out.println(account1==account2);
        //false
    }
}

结论:
Lite模式下容器启动速度快于Full模式3854<3898ms。发现User中的Account并不是IOC容器中的Account对象。用配置类本身的Bean对象执行方法创建的Account不是同一个

2. @Bean、@Component、@Controller、@Service、@Repository

该注解方式注册Bean在Spring中经常用到,不做叙述。创建的Bean也为单例模式。

实践:

//User实体类
@Component
public class User {
    private String name;
    private Account account;
    private String password;
    public User() {
    }
    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }
}

启动类中使用IOC容器获取该Bean

@SpringBootApplication
public class BootApp {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        //1.return IOC container.
        ConfigurableApplicationContext run = SpringApplication.run(BootApp.class, args);
         //2. checking loaded Bean whether have named by user1 Bean
        boolean exist = run.containsBean("user1");
        System.out.println(exist);
        //true

结论:该Bean已添加到了IOC容器中

3.@ComponentScan、@Import

@Import注解,导入指定Class数组的Bean,其Bean的名称为其全限定类名.
该注解可以在自定义配置类或者引导类(实质上也是一个配置类)进行使用或者配置在标题2中的注解标注的类上也可以生效。

@ComponentScan注解用于指定扫描哪个包路径下的Bean。SpringBoot启动类默认扫描的是其包路径以及子包下的路径。可以使用该注解扫描该路径之外的包。

实际使用:
在引导类包外创建一个Person类

@Component("person")
public class Person {
    private String name;
    private String password;
    public Person() {
    }
    public Person(String name, String password) {
        this.name = name;
        this.password = password;
    }
}
@SpringBootApplication
@ComponentScan("com.yh")
public class ImportApp {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        //1.return IOC container.
        ConfigurableApplicationContext run = SpringApplication.run(ImportApp.class, args);
        //2.by Class type to get beans
        Map<String, User> users = run.getBeansOfType(User.class);
        System.out.println(users);
        Map<String, Account> accounts = run.getBeansOfType(Account.class);
        System.out.println(accounts);
        //{com.yh.redistemplateitem.pojo.User=com.yh.redistemplateitem.pojo.User@5d5574c7}
        //{com.yh.redistemplateitem.pojo.Account=com.yh.redistemplateitem.pojo.Account@5a7a6d34}

        Person person = run.getBean("person", Person.class);
        System.out.println(person);
        //com.yh.Person@391d28ea
    }
}

4. @Conditional

条件装配:该注解有很多子类型。可以在类和方法上使用。
满足指定的条件,则进行Bean组件的注入。

其中子类型注解的实际意义通过名称即可判断大部分常用的。
在这里插入图片描述

在标题1中使用Full模式时User依赖于Account,正确场景应该为,只有当Account的Bean存在,才会创建User的Bean。那么就可以通过@ConditionalOnBean(Account.class)注解实现该效果。当Account的Bean不存在时不会创建UserBean

实践:
去除自定义配置类中的Account的@Bean注解,尝试获取User对象,结果为失败。

原生配置文件的引入@ImportResource

在使用SSM时候,有些组件的配置时使用XML文件进行配置的,进行项目升级时候可以是使用@ImportResource注解引入必要的原生xml配置文件

实践:

@SpringBootApplication
@ImportResource("classpath:beans.xml")//导入原生xml配置文件
public class BootApp {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        //1.return IOC container.
        ConfigurableApplicationContext run = SpringApplication.run(BootApp.class, args);
        //2.get Bean in XML
        User user = run.getBean("user5", User.class);
        System.out.println(user);
        Account account = run.getBean("account5", Account.class);
        System.out.println(account);
        //com.yh.redistemplateitem.pojo.User@31f5b923
        //com.yh.redistemplateitem.pojo.Account@79e2606f
      }
}

配置绑定

以前的文章中写过了,再次写一次将配置文件的值绑定为java对象的实现方式,以供理解

  1. 使用@Component+@ConfigurationProperties
    只有在IOC容器中的Bean组件(即需要@Component注解),才会拥有SpringBoot提供的绑定功能(即@ConfigurationProperties注解)
    实践:
    yaml中自定义配置
person:
  my:
   height: 100
   weight: 60kg

编写对应的实体类

@Component
@ConfigurationProperties(prefix = "person.my")
public class My {
    private int height;
    private String weight;
}

启动类中获取该Bean并输出

@SpringBootApplication
public class BootApp {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        //1.return IOC container.
        ConfigurableApplicationContext run = SpringApplication.run(BootApp.class, args);
        //2.get Bean in pojo and yaml
        My my = run.getBean("my", My.class);
        System.out.println(my);
        //My{heigth=100, weight='60kg'}
  1. 使用@EnableConfigurationProperties + @ConfigurationProperties
    使用该方式只需要实体类中去除@Component注解即可,然后在自定义配置类或者启动类或者有@Component注解的类上添加@EnableConfigurationProperties(My.class)注解即可.
    该注解的作用有两个:
    //1、开启My配置绑定功能
    //2、把这个My这个组件自动注册到IOC容器中

版权声明:本文为weixin_45466462原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。