Spring注解
EnableConfigurationProperties
如果@ConfigurationProperties是在第三方包中,那么@component是不能注入到容器的。只有@EnableConfigurationProperties才可以注入到容器。
ConditionalOnClass

componentscan的作用如下:
@ComponentScan告訴Spring 哪個packages 的用注解標(biāo)識的類 會被spring自動掃描并且裝入bean容器。
例如,如果你有個類用@Controller注解標(biāo)識了,那么,如果不加上@ComponentScan,自動掃描該controller,那么該Controller就不會被spring掃描到,更不會裝入spring容器中,因此你配置的這個Controller也沒有意義。
配置文件類比注解
@Configuation等價(jià)于<Beans></Beans>
@Bean 等價(jià)于<Bean></Bean>
@ComponentScan等價(jià)于<context:component-scan base-package="com.dxz.demo"/>
@Component 等價(jià)于<Bean></Bean>
@Bean VS @Component
兩個注解的結(jié)果是相同的,bean都會被添加到Spring上下文中。
@Component 標(biāo)注的是類,允許通過自動掃描發(fā)現(xiàn)。@Bean需要在配置類@Configuation中使用。
@Component類使用的方法或字段時(shí)不會使用CGLIB增強(qiáng)。而在@Configuration類中使用方法或字段時(shí)則使用CGLIB創(chuàng)造協(xié)作對象
假設(shè)我們需要將一些第三方的庫組件裝配到應(yīng)用中或者 我們有一個在多個應(yīng)用程序中共享的模塊,它包含一些服務(wù)。并非所有應(yīng)用都需要它們。如果在這些服務(wù)類上使用@Component并在應(yīng)用程序中使用組件掃描,我們最終可能會檢測到超過必要的bean。導(dǎo)致應(yīng)用程序無法啟動
但是我們可以使用 @Bean來加載
因此,基本上,使用@Bean將第三方類添加到上下文中。和@Component,如果它只在你的單個應(yīng)用程序中
獲取yml配置文件
/**
對接配置內(nèi)容
*/
@Data
@ConfigurationProperties(prefix = "insurance")
@Component
public class InsuranceDockingConfig {
/**
* 是否打印日志
* 0:否 1:是
*/
public String consoleType;
/**
* 項(xiàng)目負(fù)責(zé)人
*/
public String projectLeader;
/**
* 訂單負(fù)責(zé)人
*/
public String orderLeader;
}
ConditionalOnProperty 注解
1. 簡介
Spring Boot源碼中大量使用@ConditionalOnProperty來控制Configuration是否生效。
2. 實(shí)戰(zhàn)
2.1 name的用法
user類
public class User {
}
Dept類
public class Dept {
}
配置類
/**
* @Author: wgs
* @Date 2022/2/23 16:02
* @Classname Config1
* @Description 當(dāng)配置文件中只要出現(xiàn)config1.enable時(shí)(內(nèi)容為空 , 同樣也是有效的),則該配置生效。
*/
@Configuration
@ConditionalOnProperty(name = "config1.enable")
public class Config1 {
@Bean
public User user() {
User user = new User();
System.err.println("----------------初始化user--------------");
return user;
}
}
/**
* @Author: wgs
* @Date 2022/2/23 16:05
* @Classname Config2
* @Description 當(dāng)配置文件中只要出現(xiàn)config1.enable時(shí)(內(nèi)容為空,同樣也是有效的),則該配置生效。
*/
@Configuration
@ConditionalOnProperty(name = "config2.enable")
public class Config2 {
@Bean
public Dept dept() {
System.err.println("=============dept初始化========");
return new Dept();
}
}
配置文件
config1:
enable: test
啟動項(xiàng)目
2022-02-23 16:24:33.004 INFO 20313 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 459 ms
----------------初始化user--------------
2022-02-23 16:24:33.162 INFO 20313 --- [
2.2 根據(jù)配置開關(guān)進(jìn)行動態(tài)加載配置(havingValue)
在上述代碼的基礎(chǔ)上,我們首先的Config1和Config2中稍作一些修改。
配置類
/**
* @Author: wgs
* @Date 2022/2/23 16:02
* @Classname Config1
* @Description 當(dāng)配置文件中只要出現(xiàn)config1.enable時(shí)(內(nèi)容為空 , 同樣也是有效的),則該配置生效。
*/
@Configuration
// 當(dāng)配置文件中config1.enable的值為true才加載,否則就不加載
@ConditionalOnProperty(name = "config1.enable", havingValue = "true")
public class Config1 {
@Bean
public User user() {
User user = new User();
System.err.println("----------------初始化user--------------");
return user;
}
}
/**
* @Author: wgs
* @Date 2022/2/23 16:05
* @Classname Config2
* @Description 當(dāng)配置文件中只要出現(xiàn)config1.enable時(shí)(內(nèi)容為空,同樣也是有效的),則該配置生效。
*/
@Configuration
// 當(dāng)配置文件中config1.enable的值為true才加載,否則就不加載
@ConditionalOnProperty(name = "config2.enable", havingValue = "true")
public class Config2 {
@Bean
public Dept dept() {
System.err.println("=============dept初始化========");
return new Dept();
}
}
配置文件
config1:
enable: false
config2:
enable: true
啟動項(xiàng)目
2022-02-23 16:28:38.633 INFO 20439 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-02-23 16:28:38.633 INFO 20439 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 449 ms
=============dept初始化========
2022-02-23 16:28:38.830 INFO 20439 --- [
2.3 配置缺失加載配置(havingValue)
在上述代碼的基礎(chǔ)上,我們首先的Config1和Config2中稍作一些修改。
配置類
@Configuration
// 當(dāng)配置文件中config2.enable,匹配如果缺失加載
@ConditionalOnProperty(name = "config2.enable", havingValue = "true", matchIfMissing = true)
public class Config2 {
@Bean
public Dept dept() {
System.err.println("=============dept初始化========");
return new Dept();
}
}
配置文件
config1:
enable: false
啟動項(xiàng)目
2022-02-23 16:28:38.633 INFO 20439 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-02-23 16:28:38.633 INFO 20439 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 449 ms
=============dept初始化========
2022-02-23 16:28:38.830 INFO 20439 --- [
Bean的加載
在Spring Boot應(yīng)用中要讓一個普通類交給Spring容器管理,通常有以下方法:
1、使用 @Configuration與@Bean 注解
2、使用@Controller @Service @Repository @Component 注解標(biāo)注該類并且啟用@ComponentScan自動掃描
3、使用@Import 方法
其中Spring Boot實(shí)現(xiàn)自動配置使用的是@Import注解這種方式,AutoConfigurationImportSelector類的selectImports方法返回一組從META-INF/spring.factories文件中讀取的bean的全類名,這樣Spring Boot就可以加載到這些Bean并完成實(shí)例的創(chuàng)建工作。
2.2.3 自動配置總結(jié)
我們可以將自動配置的關(guān)鍵幾步以及相應(yīng)的注解總結(jié)如下:
1、@Configuration與@Bean:基于Java代碼的bean配置
2、@Conditional:設(shè)置自動配置條件依賴
3、@EnableConfigurationProperties與@ConfigurationProperties:讀取配置文件轉(zhuǎn)換為bean
4、@EnableAutoConfiguration與@Import:實(shí)現(xiàn)bean發(fā)現(xiàn)與加載
2.3 自定義starter
本小節(jié)我們通過自定義兩個starter來加強(qiáng)starter的理解和應(yīng)用。
2.3.1 案例一
2.3.1.1 開發(fā)starter
第一步:創(chuàng)建starter工程hello-spring-boot-starter并配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>cn.itcast</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
</project>
第二步:創(chuàng)建配置屬性類HelloProperties
package cn.itcast.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/*
*讀取配置文件轉(zhuǎn)換為bean
* */
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "HelloProperties{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
第三步:創(chuàng)建服務(wù)類HelloService
package cn.itcast.service;
public class HelloService {
private String name;
private String address;
public HelloService(String name, String address) {
this.name = name;
this.address = address;
}
public String sayHello(){
return "你好!我的名字叫 " + name + ",我來自 " + address;
}
}
第四步:創(chuàng)建自動配置類HelloServiceAutoConfiguration
package cn.itcast.config;
import cn.itcast.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
* 配置類,基于Java代碼的bean配置
* */
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
private HelloProperties helloProperties;
//通過構(gòu)造方法注入配置屬性對象HelloProperties
public HelloServiceAutoConfiguration(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
//實(shí)例化HelloService并載入Spring IoC容器
@Bean
@ConditionalOnMissingBean
public HelloService helloService(){
return new HelloService(helloProperties.getName(),helloProperties.getAddress());
}
}
第五步:在resources目錄下創(chuàng)建META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.itcast.config.HelloServiceAutoConfiguration
至此starter已經(jīng)開發(fā)完成了,可以將當(dāng)前starter安裝到本地maven倉庫供其他應(yīng)用來使用。
2.3.1.2 使用starter
第一步:創(chuàng)建maven工程myapp并配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>cn.itcast</groupId>
<artifactId>myapp</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--導(dǎo)入自定義starter-->
<dependency>
<groupId>cn.itcast</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
第二步:創(chuàng)建application.yml文件
server:
port: 8080
hello:
name: xiaoming
address: beijing
第三步:創(chuàng)建HelloController
package cn.itcast.controller;
import cn.itcast.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
//HelloService在我們自定義的starter中已經(jīng)完成了自動配置,所以此處可以直接注入
@Autowired
private HelloService helloService;
@GetMapping("/say")
public String sayHello(){
return helloService.sayHello();
}
}
第四步:創(chuàng)建啟動類HelloApplication
package cn.itcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class,args);
}
}
執(zhí)行啟動類main方法,訪問地址http://localhost:8080/hello/say