06-SpringBoot的一些底层注解
1、@Configuration 注解
-
使用该注解表名该类是一个配置类,该注解可以给容器中注册组件
-
@Configuration 标注的类本身也是组件
-
配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的,如下图所示:
2、Full模式与Lite模式
2.1、两种模式讲解
- Full(proxyBeanMethods = true) 【全配置。保证每个@Bean方法被调用多少次返回的组件都是单实例的。SpringBoot每次启动总会检查这个组件是否在容器中有,有的话就拿来用,没有的话再创建。增加了每次的检查时间。每次获取的都是代理对象。】
- Lite(proxyBeanMethods = false)【轻量级配置。在容器中不会保存代理对象,每个@Bean方法被调用多少次返回的组件都是新创建的,springBoot每次启动就不再检查容器中某个方法返回的值在容器中有没有,即跳过了检查,springBoot启动会增快。】
- 组件依赖必须使用Full模式默认。其他默认是否Lite模式
/**
* 1、@Configuration//告诉SpringBoot这是一个 配置类 == 配置文件
* 2、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
* 3、配置类本身也是组件
* 4、proxyBeanMethods:是不是代理bean的方法。默认true
*/
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
@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 tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("组件:"+(tom01 == tom02));
/*4、当proxyBeanMethods = true时。返回的是代理对象com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892,
*/
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
//5、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的.每次取的都是容器中的对象。
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);//true
}
}
当proxyBeanMethods = true时,返回的是代理对象:System.out.println(user == user1);//true
当proxyBeanMethods = false时,System.out.println(user == user1);//false
2.2、最佳实战(总结Full模式与Lite模式)
- 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
- 配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
2.3、Full模式与Lite模式用于解决的场景–组件依赖
pet类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pet {
private String name;
}
User类:
@Data
public class User {
private String name;
private Integer age;
private Pet pet;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
配置类:
@Configuration(proxyBeanMethods = true)//告诉springboot这是一个配置类 == 配置文件
public class MyConfig {
@Bean//给springboot组件添加容器。方法名作为组件的id;返回值类型就是组件类型;返回的值就是组件在容器中的实例。
public User user01(){
User zhangsan = new User("zhangsan", 3);
//User组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("pet01")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
1、当配置类中proxyBeanMethods = true时,以下方法返回值是true,因为两者调用的是同一个对象,都是容器中的宠物对象。即单实例。
@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、从容器中获取组件
User user01 = run.getBean("user01", User.class);
user01.getPet();
Pet pet01 = run.getBean("pet01", Pet.class);
System.out.println("两个宠物是否为同一个:" + (user01.getPet()==pet01));
}
}
2、当配置类中proxyBeanMethods = false时,每次调用的宠物对象不是容器中的对象,是新创建的。
@Configuration(proxyBeanMethods = false)//告诉springboot这是一个配置类 == 配置文件
public class MyConfig {
@Bean//给springboot组件添加容器。方法名作为组件的id;返回值类型就是组件类型;返回的值就是组件在容器中的实例。
public User user01(){
User zhangsan = new User("zhangsan", 3);
//User组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("pet01")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
方法返回值是false,因为两者调用的不是同一个对象。
2、其他可以向容器中注册组件的注解
@Bean:给容器中添加组件
@Component:代表只一个组件
@Controller:表示是一个控制器
@Service:代表它是一个业务逻辑
@Repository:代表这是一个数据库层组件
以上注解跟以前在spring中的用法一致
3、@ComponentScan@Import
/*
* @ComponentScan:指定容器中包扫描规则。通常用在主程序类型上
* @Import({User.class, DBHelper.class})
* 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名。
*/
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}
@ComponentScan:
@Import注解:
4、@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
ctrl+H:查看该注解继承树,如下所示:
注意:
1、在使用@ConditionalOnBean和@ConditionalOnMissingBean注解做判断时需要注意组件注入容器的先后顺序,结果会受组件注入容器的先后顺序影响的。
2、如果使用@ConditionalOnClass和@ConditionalOnMissingClass注解则不需要关注组件注入容器的先后顺序。
=====================条件装配,配置类中的代码==========================
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
//@ConditionalOnBean(name = "tom22")//意思是容器中有tom22组件时才创建user01组件
@ConditionalOnMissingBean(name = "tom22")//意思是容器中没有tom22组件时才创建user01组件
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom22")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
=====================条件装配,以下是主程序中的测试代码==========================
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);
}
boolean tom = run.containsBean("tom");
System.out.println("容器中Tom组件:"+tom);
boolean user01 = run.containsBean("user01");
System.out.println("容器中user01组件:"+user01);
boolean tom22 = run.containsBean("tom22");
System.out.println("容器中tom22组件:"+tom22);
}
5、原生配置文件引入(原来spring的bean.xml配置文件)
======================spring配置文件: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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="haha" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.atguigu.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
5.1、@ImportResource 导入资源
@ImportResource("classpath:beans.xml")/*允许用以前spring
配置文件的方式将组件扫描进容器内。相当于将类路径下的spring
配置文件重新解析,放到容器中。*/
public class MyConfig {
}
======================springBoot主程序中测试:看是否将上述bean.xml中的组件创建到容器中=================
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
//1、返回我们的ioc容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
}
}
6、配置绑定
如何使用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。
}
}
}
6.1、将配置文件跟一个JavaBean进行绑定
方式一 @Component +@ConfigurationProperties
Car实体类
/**
* 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
*/
@Component
@ConfigurationProperties(prefix = "mycar")//配置属性
public class Car {
private String brand;
private Integer price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
application.properties配置文件:
mycar.brance=BYD
mycar.price=100000
控制层:
@RestController
public class HelloController {
@Autowired
Car car;
@RequestMapping("/car")
public Car car(){
return car;
}
}
最后运行SpringBoot主程序
方式二 @EnableConfigurationProperties + @ConfigurationProperties
需要在配置类上加注解,使JavaBean加载到容器中:
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {
}
属性绑定:
/**
* @Description :车辆实体类
* @Author :lenovo
* @Date :2021/2/18 15:33
*/
//@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brance;
private Integer price;
public String getBrance() {
return brance;
}
public void setBrance(String brance) {
this.brance = brance;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brance='" + brance + '\'' +
", price=" + price +
'}';
}
}
配置文件:
运行结果: