四SpringBoot2核心技术——容器功能(组件添加&原生配置文件引入&配置绑定)

Posted 上善若水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四SpringBoot2核心技术——容器功能(组件添加&原生配置文件引入&配置绑定)相关的知识,希望对你有一定的参考价值。

一、组件添加

1.1、@Configuration

  • 基本使用
  • Full模式与Lite模式
    配置类组件之间无依赖关系,用Lite模式,加速容器启动过程,减少判断;
    配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式;
package com.xbmu.config;

import com.xbmu.bean.Pet;
import com.xbmu.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 1. 配置类里面使用@Bean标注在方法上给容器注册组件,默认单实例的;
 * 2. 配置类本身也是组件
 * 3. proxyBeanMethods:代理bean的方法
 *      Full(proxyBeanMethods=true) 保证每个@Bean方法被调用多少次,返回的组件都是单实例的。
 *      Lite(proxyBeanMethods=false) 每个@Bean方法被调用多少次返回的组件都是新创建的。
 *      组件依赖必须使用Full模式,默认。
 *
 */
@Configuration(proxyBeanMethods = false) // 告诉SpringBoot这是一个配置类 ===> 配置文件
public class MyConfig {
    /**
     * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象。
     * @return
     */
    @Bean // 给容器中添加组件,以方法名作为组件的id。返回类型就是组件类型,返回的值,就是组件在容器中的实例
    public User user01()
    {
        User user = new User("张三", 20);
        // user组件依赖了Pet组件
        user.setPet(dogPet());
        return user;
    }
    @Bean("dog")
    public Pet dogPet()
    {
        return new Pet("dog");
    }
}
package com.xbmu;

import com.xbmu.bean.Pet;
import com.xbmu.bean.User;
import com.xbmu.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * 主程序类
 * @SpringBootApplication : 这是一个SpringBoot应用
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        // 1.返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // 2.查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        // 3.从容器中获取组件
        Pet dog01 = run.getBean("dog", Pet.class);
        Pet dog02 = run.getBean("dog", Pet.class);
        System.out.println("组件:"+(dog01 == dog02)); // 组件:true


        // @Configuration(proxyBeanMethods = true) 输出 com.xbmu.config.MyConfig$$EnhancerBySpringCGLIB$$f678a4f6@46a145ba
        // @Configuration(proxyBeanMethods = false) 输出 com.xbmu.config.MyConfig@44032fde
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

        // 如果@Configuration(proxyBeanMethods = true) 代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
        // 保持组件单实例
        User userA = bean.user01();
        User userB = bean.user01();
        // @Configuration(proxyBeanMethods = true) 输出 true
        // @Configuration(proxyBeanMethods = false) 输出 false
        System.out.println(userA == userB);// @Configuration(proxyBeanMethods = true) 输出 true


        User user01 = run.getBean("user01",User.class);
        Pet dog = run.getBean("dog",Pet.class);
        System.out.println("用户的宠物:"+(user01.getPet() == dog));// 用户的宠物:true
    }
}

1.2、@Bean、@Component、@Controller、@Service、@Repository

@Component :标注在类上,代表是一个组件;
@Controller :标注在类上,代表是一个控制器;
@Service:标注在类上,代表是一个业务逻辑组件;
@Repository:标注在类上,代表数据库层组件;

1.3、@ComponentScan、@Import

package com.xbmu.config;

import ch.qos.logback.core.db.DBHelper;
import com.xbmu.bean.Pet;
import com.xbmu.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * 1. 配置类里面使用@Bean标注在方法上给容器注册组件,默认单实例的;
 * 2. 配置类本身也是组件
 * 3. proxyBeanMethods:代理bean的方法
 *      Full(proxyBeanMethods=true) 保证每个@Bean方法被调用多少次,返回的组件都是单实例的。
 *      Lite(proxyBeanMethods=false) 每个@Bean方法被调用多少次返回的组件都是新创建的。
 *      组件依赖必须使用Full模式,默认。
 *
 * 4. @Import({User.class, DBHelper.class})
 *    给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
 *
 */
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) // 告诉SpringBoot这是一个配置类 ===> 配置文件
public class MyConfig {
    /**
     * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象。
     * @return
     */
    @Bean // 给容器中添加组件,以方法名作为组件的id。返回类型就是组件类型,返回的值,就是组件在容器中的实例
    public User user01()
    {
        User user = new User("张三", 20);
        // user组件依赖了Pet组件
        user.setPet(dogPet());
        return user;
    }
    @Bean("dog")
    public Pet dogPet()
    {
        return new Pet("dog");
    }
}

在这里插入图片描述

1.4、@Conditional

条件装配:满足Conditional指定的条件,则进行组件注入
在这里插入图片描述

package com.xbmu.config;

import ch.qos.logback.core.db.DBHelper;
import com.xbmu.bean.Pet;
import com.xbmu.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) // 告诉SpringBoot这是一个配置类 ===> 配置文件
@ConditionalOnBean(name = "dog")
//@ConditionalOnMissingBean(name = "dog")
public class MyConfig {
    public User user01()
    {
        User user = new User("张三", 20);
        // user组件依赖了Pet组件
        user.setPet(dogPet());
        return user;
    }
    @Bean("dog2")
    public Pet dogPet()
    {
        return new Pet("dog");
    }
}
package com.xbmu;

import com.xbmu.bean.Pet;
import com.xbmu.bean.User;
import com.xbmu.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * 主程序类
 * @SpringBootApplication : 这是一个SpringBoot应用
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        // 1.返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // 2.查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        /*
        @ConditionalOnBean(name = "dog")
        输出:容器中dog组件:false
			 容器中user01组件:false
			 容器中dog2组件:false
		@ConditionalOnMissingBean(name = "dog")
		输出:容器中dog组件:false
			 容器中user01组件:true
			 容器中dog2组件:true
        */
        boolean dog = run.containsBean("dog");
        System.out.println("容器中dog组件:"+dog);

        boolean user01 = run.containsBean("user01");
        System.out.println("容器中user01组件:"+user01);

        boolean dog2 = run.containsBean("dog2");
        System.out.println("容器中dog2组件:"+dog2);
    }
}

二、原生配置文件引入

2.1、@ImportResource

src/main/resources/beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user_zs" class="com.xbmu.bean.User">
        <property name="name" value="张三"/>
        <property name="age" value="20"/>
    </bean>
    <bean id="pet_dog" class="com.xbmu.bean.Pet">
        <property name="name" value="dog"/>
    </bean>
</beans>
@ImportResource("classpath:beans.xml")
public class MyConfig {
	...
}

在这里插入图片描述

三、配置绑定

如何使用java读取到properties文件中的内容,并把它封装到javabean中,以供随时使用。
传统做法

public class getProperties {
     public static void main(String[] args) throws FileNotFoundException, IOException {
         Properties pps = new Properties();
         pps.load(new FileInputStream("a.properties"));
         Enumeration enum1 = pps.propertyNames();//得到配置文件的名字
         while(enum1.hasMoreElements()) {
             String strKey = (String) enum1.nextElement();
             String strValue = pps.getProperty(strKey);
             System.out.println(strKey + "=" + strValue);
             //封装到JavaBean。
         }
     }
 }

3.1、@Component + @ConfigurationProperties

package com.xbmu.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
 */
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
    private String brand;
    private Integer price;
    // get、set、toString方法
    ...
}

src/main/resources/application.properties

server.port=8888

mycar.brand=byd
mycar.price=150000
package com.xbmu.controller;

import com.xbmu.bean.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//@Controller
//@ResponseBody
@RestController
public class HelloController {
    @Autowired
    Car car;
    @RequestMapping("/hello")
    public String sayHello()
    {
        return "Hello,Spring Boot2 !";
    }
    @RequestMapping("/sayCar")
    public Car sayCar()
    {
        return car;
    }
}

在这里插入图片描述

3.2、@EnableConfigurationProperties + @ConfigurationProperties

@ConfigurationProperties(prefix = "mycar")
public class Car {
	...
}
@Configuration // 告诉SpringBoot这是一个配置类 ===> 配置文件
// 1. 开启Car配置绑定功能
// 2. 把这个Car组件自动注册到容器中
@EnableConfigurationProperties({Car.class})
public class MyConfig {
	...
}

以上是关于四SpringBoot2核心技术——容器功能(组件添加&原生配置文件引入&配置绑定)的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot2----容器功能

[SpringBoot2]定制化原理_SpringBoot定制化组件的几种方式

[SpringBoot2]容器功能_底层注解&配置绑定_@Configuration&@Import&@Conditional&@ImportResource&

Docker容器实战二:功能组件

学习容器你不能错过核心技术runC和Libcontainer

Spring IOC核心功能快速入门