javascript
浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包
淺談:Spring Boot原理分析(更多細節解釋在代碼注釋中)
通過@EnableAutoConfiguration注解加載Springboot內置的自動初始化類(加載什么類是配置在spring.factories),這這些類中在基于spring4.0提供的Condition接口進行Bean的初始化。
Condition
? 自定義條件:
① 定義條件類:自定義類實現Condition接口,重寫 matches 方法,在 matches 方法中進行邏輯判斷,返回
boolean值 。 matches 方法兩個參數:
? context:上下文對象,可以獲取屬性值,獲取類加載器,獲取BeanFactory等。
? metadata:元數據對象,用于獲取注解屬性。
② 判斷條件: 在初始化Bean時,使用 @Conditional(條件類.class)注解
? SpringBoot 提供的常用條件注解:
? ConditionalOnProperty:判斷配置文件中是否有對應屬性和值才初始化Bean
? ConditionalOnClass:判斷環境中是否有對應字節碼文件才初始化Bean
? ConditionalOnMissingBean:判斷環境中沒有對應Bean才初始化Bean
案列說明Condition
首先搭建springboot的項目
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><!-- 導入springboot父工程spring-boot-starter-parent,我們自己的的helloworld就成為springboot的子工程會自動引入父工程的依耐--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.fs</groupId><artifactId>springboot-condition</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- 引入starter--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- 引入redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency></dependencies></project>自定義注解
MyCondition
package com.fs.condition;import org.springframework.context.annotation.Conditional;import java.lang.annotation.*;/* 自定義注解*///元注解 @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented//判斷條件: 在初始化Bean時,使用 @Conditional(條件類.class)注解 @Conditional(ClassCondition.class) public @interface MyCondition {String[] value(); }自定義定義條件類:自定義類實現Condition接口,重寫 matches 方法,在 matches 方法中進行邏輯判斷,返回boolean值 。 matches 方法兩個參數:
? context:上下文對象,可以獲取屬性值,獲取類加載器,獲取BeanFactory等。
? metadata:元數據對象,用于獲取注解屬性。
判斷條件: 在初始化Bean時,使用 @Conditional(條件類.class)注解
在配置類中使用
package com.fs.config;import com.fs.condition.ClassCondition; import com.fs.condition.MyCondition; import com.fs.pojo.User; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration;@Configuration public class UserConfig {// @Bean // //指定一個自定義類實現Condition接口是否spring創建這bean // @Conditional(ClassCondition.class) // public User user(){ // return new User(); // }//使用自定義的Condition注解@Bean//使用自定義的注解@MyCondition("com.fs.pojo.User")public User user2(){return new User();}//指定application配置文件有這個屬性就加載bean@Bean@ConditionalOnProperty(name = "xiaofu",havingValue = "haha")public User user3(){return new User();} }application.yml
由于我們配置類中使用了@ConditionalOnProperty(name = “xiaofu”,havingValue = “haha”)
所以需要在application配置文件中編寫配置,才會讓配置類中的bean初始化
主啟動測試
package com.fs;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext;/*** @ComponentScan() 掃描引導類所在包及其子包*/ @SpringBootApplication public class SpringBootCondition {public static void main(String[] args) {//啟動springboot的應用,返回spring的IOC容器ConfigurableApplicationContext context = SpringApplication.run(SpringBootCondition.class, args);/*SpringBoot是如何知道要創建哪個Bean的?比如SpringBoot是如何知道要創建RedisTemplate的?因為我們在maven引入了spring-boot-starter-data-redis這個依耐,就會根據@Conditional注解去判斷是否初始化這個bean*///獲取bean,獲取redisTemplateObject redisTemplate = context.getBean("redisTemplate");System.out.println(redisTemplate);//我們自定義了配置類,UserConfig 類中的方法也加上了@Condition注解來判斷是否注入這個Object user2 = context.getBean("user2");System.out.println(user2);//使用springboot提供的注解來判斷是否初始化beanObject user3 = context.getBean("user3");System.out.println(user3);} }說明我們自定義的Condition 條件判斷沒有問題
切換內置web服務器
<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>如何自定義Stater?(@Import 自定義Enable注解 spring.factories 等)
@Enable*注解
SpringBoot中提供了很多Enable開頭的注解,這些注解都是用于動態啟用某些功能的。而其底層原理是使用@Import注解導入一些配置類,實現Bean的動態加載。
@Import注解
@Enable*底層依賴于@Import注解導入一些類,使用@Import導入的類會被Spring加載到IOC容器中。而@Import提供4中用法:
① 導入Bean
② 導入配置類 @Import(spring配置類.class)
③ 導入 ImportSelector 實現類。一般用于加載配置文件中的類
④ 導入 ImportBeanDefinitionRegistrar 實現類。
@EnableAutoConfiguration 注解
? @EnableAutoConfiguration 注解內部使用 @Import(AutoConfigurationImportSelector.class)來加載配置類。
? 配置文件位置:META-INF/spring.factories,該配置文件中定義了大量的配置類,當 SpringBoot 應用啟動時,會自動加載這些配置類,初始化Bean
? 并不是所有的Bean都會被初始化,在配置類中使用Condition來加載滿足條件的Bean
實現步驟
① 創建 redis-spring-boot-autoconfigure 模塊
② 創建 redis-spring-boot-starter 模塊,依賴 redis-springboot-autoconfigure的模塊
③ 在 redis-spring-boot-autoconfigure 模塊中初始化 Jedis 的
Bean。并定義META-INF/spring.factories 文件
④ 在測試模塊中引入自定義的 redis-starter 依賴,測試獲取
Jedis 的Bean,操作 redis。
① 創建 redis-spring-boot-autoconfigure 模塊
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><!-- 導入springboot父工程spring-boot-starter-parent,我們自己的的helloworld就成為springboot的子工程會自動引入父工程的依耐--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.fs</groupId><artifactId>redis-spring-boot-autoconfigure</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--引入jedis依賴--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency></dependencies></project>RedisAutoConfiguration 自定義的AutoConfiguration類
package com.fs.config;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 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; import redis.clients.jedis.Jedis;/* 自定義的AutoConfiguration類*/ @Configuration //這個注解會去找我們給的的Class.class,并且這個類要被@ConfigurationProperties注解標記 //說白了 @EnableConfigurationProperties 相當于把使用 @ConfigurationProperties 的類進行了一次注入。 @EnableConfigurationProperties(RedisProperties.class) //這個注解表示判斷環境中是否有對應字節碼文件才初始化Bean,判斷是否導入了Jedis的包,當前項目環境中有沒有Jedis這個類 //有才會去初始化我們當前類下方法的bean @ConditionalOnClass(Jedis.class) public class RedisAutoConfiguration {@Bean//這個Condition注解的意思就是判斷環境中沒有對應Bean才初始化Bean,//IOC容器中有么有名為jedis的bean,有就不初始化我們這個bean@ConditionalOnMissingBean(name="jedis")public Jedis jedis(RedisProperties redisProperties){//初始化bean,并將我們的屬性類中的值給這個beanreturn new Jedis(redisProperties.getHost(),redisProperties.getPort());} }RedisProperties 自定義的簡陋的redis連接屬性類
package com.fs.config; /* 自定義的簡陋的redis連接屬性類*/import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; //docker start -i 容器名稱 @Component //ConfigurationProperties這個注解就會去application.yml中去找對應的一組屬性值,并賦值給我們自定義的屬性類的成員變量 @ConfigurationProperties(prefix = "xiaofu.redis") public class RedisProperties {//提供2個屬性,從application配置文件中去讀取.指定默認指,用戶不在application中配置,就使用默認的private String host = "localhost";private Integer port = 6379;public String getHost() {return host;}public void setHost(String host) {this.host = host;}public Integer getPort() {return port;}public void setPort(Integer port) {this.port = port;} }User 實體類,用于測試自定義@Enable注解使用
package com.fs.pojo;public class User { }UserConfig User配置類,注入User Bean
package com.fs.config;import com.fs.pojo.User; import org.springframework.context.annotation.Bean;public class UserConfig {@Beanpublic User user(){return new User();} }EnableAutoUser 自定義Enable注解
package com.fs.enable;import com.fs.config.UserConfig; import org.springframework.context.annotation.Import;import java.lang.annotation.*; //元注解信息 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented //自定義注解,當加上這個注解,就會自動將配置類中的bean注入到IOC容器中 @Import(UserConfig.class) public @interface EnableAutoUser { }spring.factories 自定義starter核心的配置文件
# 這個配置文件一定要在resources/META-INF/spring.factories下 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.fs.config.RedisAutoConfiguration② 創建 redis-spring-boot-starter 模塊,依賴 redis-springboot-autoconfigure的模塊
創建starter工程(遵循Spring starter命名規范)
pom.xml 主要引入我們自定義的 redis-springboot-autoconfigure
<?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><!-- 導入springboot父工程spring-boot-starter-parent,我們自己的的helloworld就成為springboot的子工程會自動引入父工程的依耐--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.fs</groupId><artifactId>redis-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version><dependencies><!--引入自定義的redis-configure--><dependency><groupId>com.fs</groupId><artifactId>redis-spring-boot-autoconfigure</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies> </project>創建springboot工程測試我們自定義的starter 模塊
pom.xml 引入我們自定義的 redis-spring-boot-starter 模塊
<?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><!-- 導入springboot父工程spring-boot-starter-parent,我們自己的的helloworld就成為springboot的子工程會自動引入父工程的依耐--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.fs</groupId><artifactId>test-Redis-restart</artifactId><version>1.0-SNAPSHOT</version><dependencies> <!-- 引入自定義的restart--><dependency><groupId>com.fs</groupId><artifactId>redis-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies> </project>application.yml
# 使用我們自定義的autoconfigure 的RedisProperties 屬性類@ConfigurationProperties(prefix = "xiaofu.redis") xiaofu:redis:host: 47.112.174.148port: 6379主啟動 MyStarterApp
package com.fs;import com.fs.enable.EnableAutoUser; import com.fs.pojo.User; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import redis.clients.jedis.Jedis;@SpringBootApplication //使用自定義的注解,就會自動加載自定義注解上@Import(UserConfig.class)的配置類,注入bean @EnableAutoUser public class MyStarterApp {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(MyStarterApp.class, args);//從容器中獲取我們自定義的Jedis,//由于@SpringBootApplication注解中的@EnableAutoConfiguration//會自動去加載META-INF/spring.factories,該配置文件中定義了大量的配置類//我們自定義的redis-spring-boot-autoconfigure項目也寫了一個spring.factories,所以就會把我們自定義的RedisAutoConfiguration配置類加載初始化beanJedis bean = context.getBean(Jedis.class);System.out.println(bean);//由于我們配置文件中指定了host地址,測試一下bean.set("haha","xixi");String haha = bean.get("haha");System.out.println(haha);//獲取userUser user = context.getBean(User.class);System.out.println(user);} }測試結果
SpringBoot 監控概述
SpringBoot自帶監控功能Actuator,可以幫助實現對程序內部運行情況監控,比如監控狀況、Bean加載情況、配置屬性、日志信息等。
SpringBoot 監控使用
① 導入依賴坐標
org.springframework.boot
spring-boot-starter-actuator
② 訪問http://localhost:8080/acruator
SpringBoot 監控 - Spring Boot Admin
SpringBoot 監控 - Spring Boot Admin
? Spring Boot Admin是一個開源社區項目,用于管理和監控SpringBoot應用程序。
? Spring Boot Admin 有兩個角色,客戶端(Client)和服務端(Server)。
? 應用程序作為Spring Boot Admin Client向為Spring Boot Admin Server注冊
? Spring Boot Admin Server 的UI界面將Spring Boot Admin Client的Actuator Endpoint上的一些監控信息。
使用步驟
admin-server:
① 創建 admin-server 模塊
② 導入依賴坐標 admin-starter-server
③ 在引導類上啟用監控功能@EnableAdminServer
admin-client:
① 創建 admin-client 模塊
② 導入依賴坐標 admin-starter-client
③ 配置相關信息:server地址等
④ 啟動server和client服務,訪問server
Spring Boot Admin 項目搭建
springboot-admin-service
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><!-- 導入springboot父工程spring-boot-starter-parent,我們自己的的helloworld就成為springboot的子工程會自動引入父工程的依耐--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.fs</groupId><artifactId>springboot-admin-service</artifactId><version>1.0-SNAPSHOT</version><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.3.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>application.yml
server:port: 9000主啟動 SpringbootAdminService
package com.fs;import de.codecentric.boot.admin.server.config.EnableAdminServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;//開啟adminserver @EnableAdminServer @SpringBootApplication public class SpringbootAdminService {public static void main(String[] args) {SpringApplication.run(SpringbootAdminService.class,args);} }springboot-admin-client
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><!-- 導入springboot父工程spring-boot-starter-parent,我們自己的的helloworld就成為springboot的子工程會自動引入父工程的依耐--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.fs</groupId><artifactId>springboot-admin-client</artifactId><version>1.0-SNAPSHOT</version><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-client --><dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId><version>2.3.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>application.yml
spring:boot:admin:client:url: http://127.0.0.1:9000 # 注意這里必須寫ip 指定adminserver的地址application:name: xiaofu-springboot management:endpoint:health:show-details: alwaysendpoints:web:exposure:include: "*" # 將所有的監控endpoint暴露出來主啟動 SpringbootAdminClient
package com.fs;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class SpringbootAdminClient {public static void main(String[] args) {SpringApplication.run(SpringbootAdminClient.class,args);} }controller
package com.fs.controller;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController @RequestMapping("/hello") public class TestController {@RequestMapping("/world")public String add(){return "HelloWorld";} }啟動兩個項目,打開瀏覽器測試
就可以一目了然啦
springboot的項目打成war包
==1 改造啟動類 ==
package com.fs;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;/* 將springboot的項目打成war包1.先在pom文件中設置war2.將主啟動類extends SpringBootServletInitializer3.重寫SpringApplicationBuilder configure(SpringApplicationBuilder builder){}方法4.在configure方法中返回builder.sources(主啟動.class);*/ @SpringBootApplication public class HelloWorld extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(HelloWorld.class,args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(HelloWorld.class);} }2 改造POM.xml
<packaging>war</packaging>
點名maven的package就能得到war包的springboot項目啦
總結
以上是生活随笔為你收集整理的浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈SpringBoot的基本概念与简单
- 下一篇: SpringCloud微服务架构,Spr