Spring Boot基礎(一)自動配置:配置文件與@Condition


Spring Boot 解決快啟動與運行Spring項目的問題,Spring配置依賴比較繁瑣。它不是對Spring功能上的增強,而是提供了一種快速使用Spring的方式。

  • 自動配置:項目啟動時,配置自動選擇
  • 起步依賴:使用Maven項目對象模型,將一些搭配使用的包打包在一起
  • 其他:提供一些大型項目中常用的非功能特性,如嵌入式服務器

起步依賴原理

1. spring-boot-starter-parent

定義了各類技術的版本信息,組合了一套最優搭配的功能版本。在各種starts中定義了該功能所需的做標記he,大部分版本信息來自父工程,因此並不會導致版本沖突

2. spring-boot-starter-web

Sprint Boot 配置文件

定義

properties:鍵值對形式,參數=值。是默認的配置文件

yml / yaml:參數.小參數: 空格 (冒號后面是有空格的)

  • yml 以數據為核心,比傳統的xml方式更簡潔,不用寫標簽;比簡介的properties更完整,可以看到上層參數
  • 大小寫敏感;數據值前有空格;使用縮進代表層級關系,且縮進不允許用 tab,只能用空格(IDEA無需關注);#代表空格
  • 數據格式
#對象
person: name: zhangsan #或者使用行內寫法,少用 person: {name: zhangsan}

#數組
address:
  - bejing #帶空格
  - shanghai
#行內寫法
address:{bejing,shanghai}

#純量(常量)
msg: 'hello \n word' #使用單引號,忽略轉義字符,直接輸出\n
msg: "hello \n word" #使用雙引號,識別轉義字符,\n識別為換行
  • 參數引用:${ arg }

三種配置文件優先級:properties>yml>yaml。若配置文件中配置了相同的參數,則讀取優先級更高的

 讀取

  •  @Value:使用注解在代碼的變量中引用,如:@Value("${name}") private String name;。單個引用,數量較多時比較繁雜
  • Environment對象:environment對象+Autowired注解。只需注入一次就可以全局使用。如:@Autowired private Environment environment; 引用參數時直接使用其getProperty即可
  • @CpnfigurationProperties:將一個實體類作為配置文件類。實體類的變量對應配置文件中的參數。但要注意,使用這種方法獲取參數時,名字需要完整,如果想獲取二級參數,需要在添加前綴,前綴就是一級參數名,例如獲取person下的所有參數,應寫成這樣:@ConfigurationProperties(prefix = "person")。這樣在使用get方法時,就會准確定位到想要的參數

 補充知識:

@Component:確保被Spring Boot所識別,是一個Been

添加@CpnfigurationProperties時配置文件會報紅,添加以下依賴即可

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-configuration-processor</artifactId>
   <scope>true</scope>
</dependency>

 

profile配置

properties方式

當存在多個配置文件時,需要激活后方可使用,否則就使用默認的,可以看到,未激活時項目啟動顯示:

2021-12-26 14:23:02.165  INFO 1420 --- [           main] c.e.s.SpringbootProfileApplication       : No active profile set, falling back to default profiles: default

 

 而當需要另一個配置文件生效時(激活),在application.properties文件中配置:spring.profiles.active=dev 即可。這里的dev就是配置文件的標記。當配置多個配置文件時,文件命名應按照如下格式,application后應該使用-來區分環境:

application.properties
application-dev.properties
application-prd.properties
application-test.properties

標記某配置文件后,讀取配置時就會選擇所標記的文件,而啟動項目時,也會顯示日志:

2021-12-26 14:26:47.815  INFO 7808 --- [           main] c.e.s.SpringbootProfileApplication       : The following profiles are active: dev

 

 yml方式

yml內部使用 --- 三條短杠為分隔符將一個yml文件分為多個部分,環境名使用spring.profiles:xxx 來區分,激活時用spring.profile.active:xxx。這樣使得在一個yml配置文件中就存在不同的配置環境

 

 補充:

激活方式②:虛擬機命令激活:在右上角配置一欄選擇設置配置文件,並在VM options中填寫:-Dspring.profiles.active=xxx  這樣也可以激活配置文件,並且優先級比配置文件要高

 

 

激活方式③:命令行激活:在運行jar包時帶入外部參數:--spring.profiles.active=prd 即可切換不同的環境

 

 綜上所述,boot項目的配置文件既有內部的,也有外部的。因此他們的加載順序自然是不同的。這里列舉一些內部位置:

  1. file:./config/:當前項目下的/config目錄——即在當前項目的根目錄下創建一個config目錄,里面的配置文件是優先級最高的
  2. file:./:當前項目的根目錄 ——即當前項目根目錄,在IDEA頁面使用Project File頁面新建一個配置文件,這個配置文件的優先級是2,僅次於1
  3. classpath:/config/:classpath下的/config/目錄:即resource/config/目錄下的配置文件,/config文件本是沒有的,但創建后,里面的配置文件優先級就比外部根目錄的要高了
  4. classpath/:classpath的根目錄——即resource下的application.properties文件,默認的配置文件(yml也是)
  5. 注意:由於file:./config/和file:/下的文件並不符合maven的結構,所以不會打進jar包

 外部位置。官方定義了十多個外部可引用的位置,但實際用到的卻不多:

  1.  命令行(會比上面的4、5優先級高)
    1. 在運行jar包時指定啟動參數   E:\Work\Workspace\springboot-config\target>java -jar springboot-config-0.0.1-SNAPSHOT.jar --server.port=8079
    2. 也可以在運行jar包時指定外部配置文件  E:\Work\Workspace\springboot-config\target>java -jar springboot-config-0.0.1-SNAPSHOT.jar --spring.config.location=e://application.properties
  2.  將配置文件直接放在於jar包同級的目錄下,則會自動讀取
  3. 建立與jar包同級的/config/application.properties目錄文件,也可以讀取到
E:\Work\Workspace\springboot-config\target>java -jar springboot-config-0.0.1-SNAPSHOT.jar --spring.config.location=e://application.properties

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

2021-12-26 15:41:46.188  INFO 4932 --- [           main] c.e.s.SpringbootConfigApplication        : Starting SpringbootConfigApplication v0.0.1-SNAPSHOT using Java 1.8.0_181 on DESKTOP-FPG6BLH with PID 4932 (E:\Work\Workspace\springboot-config\target\springboot-config-0.0.1-SNAPSHOT.jar started by Administrator in E:\Work\Workspace\springboot-config\target)
2021-12-26 15:41:46.201  INFO 4932 --- [           main] c.e.s.SpringbootConfigApplication        : No active profile set, falling back to default profiles: default
2021-12-26 15:41:47.706  INFO 4932 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8078 (http)
……

 

 springboot設置這么多配置的原因就是在項目啟動后如果配置錯誤,可以使用外部配置來替代內部配置。而無需修改內部配置

(說起來,如果配置有誤,難道不要重啟項目才會讀取嗎?既然都重啟了,為啥不直接改呢(可能是熱部署模式下可以不用重啟項目就可以讀取新配置吧!))

 

 整合Junit

 整合框架需要注意的點

  • 該打的注解不能少,Service層需要加@Service,測試主類需要加@SpringBootTest,並指定對應的主類:@SpringBootTest(classes = SpringbootJunitApplication.class)
  • 如果測試所在的包與主類所在的包是同一級或者在它的子包,就無需使用SpringBootTest去指定主類
  • 由快速構建出來的Spring Boot項目,它的測試包和主類包是一致的(flag:個人還未驗證)

 整合MyBatis

 (補充)

 

 SprintBoot切換內置服務器

配置類:EmbeddedWebServerFactoryCustomizerAutoConfiguration

注:可在pom.xml右鍵選擇diagrams查看編輯里面的內容

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 排除tomcat依賴 -->
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 加入jetty依賴 -->
        <dependency>
            <artifactId>spring-boot-starter-jetty</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>

選擇性的創建Bean:Condition 注解

在Sprintboot中獲取Bean

//啟動SpringBoot,獲取Ioc容器
ConfigurableApplicationContext context = SpringApplication.run(SprintbootMyUnApplication.class, args);

//當字節碼文件存在時,創建bean后在這里可以獲取到userbaen
Object user = context.getBean("user");
System.out.println(user);

 

介紹:條件接口——Condition

 
         
@FunctionalInterface
//實現該接口並重寫matches方法,自定義判斷條件
public interface Condition {
  //返回值是一個boolean值,為true則創建bean,為false不創建
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}
 

 

實現條件接口,並重寫方法:

/**
 * 自定義的條件類,根據類是否存在決定是否創建bean
 * 實現Condition接口,重寫matches方法,並在里面進行邏輯判斷
 * 返回boolean值,true則創建,false不創建
 */
public class ClassCondition implements Condition {

    /**
     * @param context 上下文對象,用於獲取環境,IOC容器,Classloader對象
     * @param metadata 注解元對象,用於獲取注解定義的屬性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        boolean flag = true;
        //1.根據是否導入指定依賴坐標來判斷是否創建User Bean
//        try {
//            //判斷對應文件是否存在
//            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
//        } catch (ClassNotFoundException e) {
//            flag = false;
//        }
        //2.導入通過注解屬性值val指定坐標創建bean
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        String[] val = (String[])annotationAttributes.get("val");
        try {
            for (String className : val) {
                //判斷對應文件是否存在
                Class<?> aClass = Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            flag = false;
        }
        return flag;
    }
}

 

sprintboot自動配置包:org.sprintbootframework.boot.autoconfigure,其中的condition包內有多個ConditionOnxxxx的類,就是按照各種條件來決定是否創建Bean的方法

按照properties內是否存在某屬性的鍵值對來檢測是否創建該bean

  @Bean
    @ConditionalOnProperty(name = "xiaozhou", havingValue = "zzz")  //當name和value的值存在時,才會創建這個bean
  //獲取baen的時候以這個方法名為准
  public User user(){
        return new User(); }

 

總結:

  1. 定義條件類:自定義實現Condition接口,重寫matches方法,在matches方法中進行邏輯判斷,返回boolean值
  2. 判斷條件:在初始化Bean時,使用@Conditional(條件類.class)注解

 

 

自動配置的關鍵:Enable注解

Springboot中提供了很多Enable開頭的注解,這些注解都是用於動態啟動某些功能的,而底層原理是使用@Import注解導入一些類,實現Bean的動態加載

 @EnableAutoConfiguration 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})   //使用import注解導入配置類,實現Bean的動態加載
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

 

 手動掃描包,讓SpringBoot添加其為Bean掃描范圍

/**
 * ComponentScan掃描范圍是當前引導類所在包以及其子包
 * 如果不是,可使用以下方法獲取bean
 * 1.在當前啟動類上添加@ComponentScan("包名“)
 * 2.使用@Import注解加載類,這些類都會被Sprint創建,並放入Ioc容器
 * 3.對Import注解進行封裝,讓sprintboot識別到並加載進來
 */

@SpringBootApplication
//@ComponentScan("com.yz.config")
//@Import(UserConfig.class)
@EnableUser  //在EnableUser中封裝Import
public class SprintbootMyUnApplication {
………………
}

 

  Enbale注解

import com.yz.config.UserConfig;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;
//這三個是Import的元注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)  //在這里添配置類
public @interface EnableUser {
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM