- 二、底层注解
- 2.1 容器功能
- 2.1.1. @Configuration
- 2.2.1.1. 基本使用
- 2.2.1.2. 全模式(Full Mode)和轻量级模式(Lite Mode)
- 2.2.1.3. 其他同类型注解
- 2.1.2. @import
- 2.2.1.1. 基本使用
- 2.1.3. @Conditional
- 2.1.4. @importResource
- 2.1.5. @ConfigurationProperties
- 2.1.5.1. @Component + @ConfigurationProperties
- 2.1.5.1. @ConfigurationProperties
User.java
package cn.com.springboot.demo.bean;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString
@NoArgsConstructor
public class User {
private String name;
private String age;
public User(String name, String age) {
this.name = name;
this.age = age;
}
}
Pet.java
package cn.com.springboot.demo.bean;
import lombok.*;
@Setter
@Getter
@ToString
@NoArgsConstructor
public class Pet {
private String breed;
private String petName;
public Pet(String breed, String petName) {
this.breed = breed;
this.petName = petName;
}
}
MyConfig01.java
package cn.com.springboot.demo.config;
import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig01 {
@Bean
public User user01() {
return new User("张三", "27");
}
@Bean("myPet")
public Pet pet01() {
return new Pet("cat", "27");
}
}
- @Configuration:告诉 spring-boot 这是一个配置类,也就是配置文件
- @Bean:将该方法注册为一个组件,添加到容器中
- 组件 ID:方法名就是这个组件的组件 ID
- 返回值:组件在容器中实例
- @Bean(“myPet”):定义 ID 为 myPet 的组件
- 配置类本身也是一个组件
- 注册的组件,默认是单实例的
MainApp.java
package cn.com.springboot.demo;
import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
User user01 = run.getBean("user01", User.class);
Pet myPet = run.getBean("myPet", Pet.class);
System.out.println(user01);
System.out.println(myPet);
}
}
运行结果
User(name=张三, age=27) Pet(breed=cat, petName=27)2.2.1.2. 全模式(Full Mode)和轻量级模式(Lite Mode)
@Configuration 注解在 spring-boot 2 中多了以下的属性:
... boolean proxyBeanMethods() default true; ...
默认值是 true 。如果 @Configuration(proxyBeanMethods = true) ,那么则是使用代理对象调用方法。spring-boot 总会检查这个组件是否存在容器中,如果存在则返回该组件,以此保证组件的单实例。如果 @Configuration(proxyBeanMethods = false),则会跳过上述检查,每次在调用组件时,都会返回新的组件。
- Full Mode: proxyBeanMethods = true
- 配置的组件如果有依赖关系,方法调用单实例组件
- Lite Mode:proxyBeanMethods = false
- 配置的组件如果没有依赖关系,跳过检查过程,加速容器启动
示例代码
proxyBeanMethods = true 的情况:
MyConfig01.java
package cn.com.springboot.demo.config;
import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = true)
public class MyConfig01 {
@Bean
public User user01() {
return new User("张三", "27");
}
@Bean("myPet")
public Pet pet01() {
return new Pet("cat", "27");
}
}
MainApp.java
package cn.com.springboot.demo;
import cn.com.springboot.demo.bean.User;
import cn.com.springboot.demo.config.MyConfig01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
// 测试 MyConfig01 的 Full Mode 和 Lite Mode
MyConfig01 bean = run.getBean(MyConfig01.class);
User user01 = bean.user01();
User user02 = bean.user01();
System.out.println("Full Mode:" + (user01 == user02));
}
}
运行结果
Full Mode:true
proxyBeanMethods = false 的情况:
MyConfig01.java
package cn.com.springboot.demo.config;
import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyConfig01 {
@Bean
public User user01() {
return new User("张三", "27");
}
@Bean("myPet")
public Pet pet01() {
return new Pet("cat", "27");
}
}
MainApp.java
package cn.com.springboot.demo;
import cn.com.springboot.demo.bean.User;
import cn.com.springboot.demo.config.MyConfig01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
// 测试 MyConfig01 的 Full Mode 和 Lite Mode
MyConfig01 bean = run.getBean(MyConfig01.class);
User user01 = bean.user01();
User user02 = bean.user01();
// System.out.println("Full Mode:" + (user01 == user02));
System.out.println("Lite Mode:" + (user01 == user02));
}
}
运行结果
Lite Mode:false2.2.1.3. 其他同类型注解
以前用于注册组件的注解也是可以使用的,如:
@Component // 泛指组件,将该组件交给 Spring 管理 @Controller // 作用于 controller 上,将该组件交给 Spring 管理 @Service // 作用于逻辑实现类上,将该实现类交给 Spring 管理 @Repository // 作用于持久层的接口上,将该接口的实现类交给 Spring 管理 @ComponentScan // 定义包扫描规则2.1.2. @import 2.2.1.1. 基本使用
通过调用指定类的无参构造,将指定类型的组件导入到容器中,可以使用数组传递多个。如:
示例
MyConfig01.java
package cn.com.springboot.demo.config;
import ch.qos.logback.core.db.DBHelper;
import cn.com.springboot.demo.bean.User;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.import;
@import({User.class, DBHelper.class})
@Configuration
public class MyConfig02 {}
MainApp.java
package cn.com.springboot.demo;
import ch.qos.logback.core.db.DBHelper;
import cn.com.springboot.demo.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Arrays;
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
// 测试 MyConfig01 的 Full Mode 和 Lite Mode
// MyConfig01 bean = run.getBean(MyConfig01.class);
// User user01 = bean.user01();
// User user02 = bean.user01();
// System.out.println("Full Mode:" + (user01 == user02));
// System.out.println("Lite Mode:" + (user01 == user02));
// System.out.println("---------------------------------------");
String[] beans = run.getBeanNamesForType(User.class);
Arrays.asList(beans).forEach(System.out::println);
String[] beans2 = run.getBeanNamesForType(DBHelper.class);
Arrays.asList(beans2).forEach(System.out::println);
}
}
运行结果
cn.com.springboot.demo.bean.User ch.qos.logback.core.db.DBHelper
- @import 导入组件的默认名字:全类名
- 例:ch.qos.logback.core.db.DBHelper
满足一定的条件时,才向容器中注入组件。@Conditional 存在很多派生注解,如:
| 派生注解名 | 说明 |
|---|---|
| ConditionalOnWebApplication | 当前项目是Web项目 |
| ConditionalOnJava | 基于 Java 版本 |
| ConditionalOnJndi | 基于 JNDI 存在 |
| ConditionalOnWarDeployment | 当应用程序为传统 WAR 部署 |
| ConditionalOnSingleCandidate | 当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选Bean |
| ConditionalOnProperty | 指定的属性是否有指定的值 |
| Profile | 指定的 Profile 被激活 |
| ConditionalOnMissingBean | 当容器里没有指定 Bean |
| ConditionalOnCloudPlatform | 当指定的云平台处于活动状态 |
| ConditionalOnClass | 当类路径下有指定类 |
| ConditionalOnMissingClass | 当类路径下没有指定类 |
| ConditionalOnResource | 类路径是否有指定的值 |
| ConditionalOnRepositoryType | 已启用的特定类型的 Spring 数据仓库 |
| ConditionalOnNotWebApplication | 当前项目不是Web项目 |
| ConditionalOnBean | 当容器里有指定 Bean |
| ConditionalOnDefaultWebSecurity | Web Security 可用并且用户没有自定义配置 |
| ConditionalOnEnabledResourceChain | 检查Spring资源处理链是否启用。匹配WebProperties.Resources.Chain.getEnabled()是否为真,或者webjar -locator-core是否在类路径上 |
| ConditionalOnexpression | 基于 SpEL 表达式 |
示例(ConditionalOnBean,当存在 pet03 时,才向容器中添加 user01)
MyConfig03.java
package cn.com.springboot.demo.config;
import cn.com.springboot.demo.bean.Pet;
import cn.com.springboot.demo.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig03 {
@ConditionalOnBean(name = "pet01")
@Bean
public User user03() {
return new User("张三", "27");
}
@Bean("pet")
public Pet pet03() {
return new Pet("cat", "coco");
}
}
MainApp.java
package cn.com.springboot.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
// 测试 MyConfig03 的 @ConditionalOnBean
System.out.println(run.containsBean("user03"));
}
}
运行结果
false
- @ConditionalOnBean(name = “pet01”) 可以加在方法上也可以加在类上
- 方法上:当条件不满足时,只有当前方法不会注册
- 类上:当条件不满足时,整个类中的组件都不会注册
导入原生的配置文件。如果之前就存在使用 XML 配置组件的方式或者第三方使用 XML 配置的组件方式,需要向项目中导入此类配置时使用。如:
示例
beans.xml
Myconfig04.java
package cn.com.springboot.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.importResource;
@Configuration
@importResource("classpath:beans.xml")
public class MyConfig04 {}
MainApp.java
package cn.com.springboot.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApp.class, args);
// 测试 MyConfig04 的 @importResources
System.out.println(run.containsBean("user04"));
System.out.println(run.containsBean("pet04"));
}
}
运行结果
true true2.1.5. @ConfigurationProperties
配置绑定。在开发中一般将一些变化的东西写在 properties 文件中。如,DB连接信息等。
2.1.5.1. @Component + @ConfigurationProperties示例
Car.java
package cn.com.springboot.demo.bean;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Setter
@Getter
@ToString
@NoArgsConstructor
@Component
@ConfigurationProperties("car01")
public class Car {
private String brand;
private String price;
public Car(String brand, String price) {
this.brand = brand;
this.price = price;
}
}
application.properties
car01.brand=BMW car01.price=1200000
CarController.java
package cn.com.springboot.demo.controller;
import cn.com.springboot.demo.bean.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CarController {
@Autowired
private Car car;
@RequestMapping("/car")
public Car myCar() {
return car;
}
}
运行结果
- @Component:将 Car 注册为一个组件,才能拥有 spring-boot 提供的功能
- @ConfigurationProperties:指定配置文件的前缀
示例
Car.java
package cn.com.springboot.demo.bean;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Setter
@Getter
@ToString
@NoArgsConstructor
// @Component
@ConfigurationProperties("car02")
public class Car {
private String brand;
private String price;
public Car(String brand, String price) {
this.brand = brand;
this.price = price;
}
}
application.properties
car02.brand=LEXUS car02.price=1800000
CarController.java
package cn.com.springboot.demo.controller;
import cn.com.springboot.demo.bean.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CarController {
@Autowired
private Car car;
@RequestMapping("/car")
public Car myCar() {
return car;
}
}
MyConfig05.java
package cn.com.springboot.demo.config;
import cn.com.springboot.demo.bean.Car;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(Car.class)
public class MyConfig05 {}
运行结果
- @ConfigurationProperties:指定配置文件的前缀
- @EnableConfigurationProperties(${value}):
- 开启指定 ${value} 的配置绑定功能
- 将 ${value} 组件注册到容器中
- 必须写在配置类上



