springboot starter工作原理_springboot基础知识集结,你get到了吗
導讀
首發于公眾號:JAVA大賊船,原創不易,喜歡的讀者可以關注一下哦!一個分享java學習資源,實戰經驗和技術文章的公眾號!
一、SpringBoot的特點
Spring Boot 主要目標是:
- 為所有 Spring 的開發者提供一個非??焖俚摹V泛接受的入門體驗
- 開箱即用(啟動器starter-其實就是SpringBoot提供的一個jar包),但通過自己設置參數(.properties),即可快速擺脫這種方式。
- 提供了一些大型項目中常見的非功能性特性,如內嵌服務器、安全、指標,健康檢測、外部化配置等
- 絕對沒有代碼生成,也無需 XML 配置。
更多細節,可以到官網查看。
二、 SpringBoot的核心功能
- 起步依賴
起步依賴本質上是一個Maven項目對象模型(Project Object Model,POM),定義了對其他庫的傳遞依賴,這些東西加在一起即支持某項功能。
簡單的說,起步依賴就是將具備某種功能的坐標打包到一起,并提供一些默認的功能。 - 自動配置
Spring Boot的自動配置是一個運行時(更準確地說,是應用程序啟動時)的過程,考慮了眾多因素,才決定Spring配置應該用哪個,不該用哪個。該過程是Spring自動完成的。
三、SpringBoot原理分析
起步依賴原理分析
分析spring-boot-starter-parent
按住Ctrl點擊pom.xml中的spring-boot-starter-parent,跳轉到了spring-boot-starter-parent的pom.xml,xml配置如下(只摘抄了部分重點配置):
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.2.RELEASE</version><relativePath>../../spring-boot-dependencies</relativePath></parent>按住Ctrl點擊pom.xml中的spring-boot-starter-dependencies,跳轉到了spring-boot-starter-dependencies的pom.xml,xml配置如下(只摘抄了部分重點配置):
<properties><activemq.version>5.15.11</activemq.version><antlr2.version>2.7.7</antlr2.version><appengine-sdk.version>1.9.77</appengine-sdk.version><artemis.version>2.10.1</artemis.version><aspectj.version>1.9.5</aspectj.version><assertj.version>3.13.2</assertj.version><atomikos.version>4.0.6</atomikos.version><awaitility.version>4.0.1</awaitility.version><bitronix.version>2.1.4</bitronix.version><build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>... ... ... </properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot</artifactId><version>2.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><version>2.2.2.RELEASE</version></dependency>... ... ...</dependencies> </dependencyManagement><build><pluginManagement><plugins><plugin><groupId>org.apache.johnzon</groupId><artifactId>johnzon-maven-plugin</artifactId><version>${johnzon.version}</version></plugin><plugin><groupId>org.jetbrains.kotlin</groupId><artifactId>kotlin-maven-plugin</artifactId><version>${kotlin.version}</version></plugin>... ... ...</plugins></pluginManagement> </build>從上面的spring-boot-starter-dependencies的pom.xml中可以發現,一部分坐標的版本、依賴管理、插件管理已經定義好,所以我們的SpringBoot工程繼承spring-boot-starter-parent后已經具備版本鎖定等配置了。所以起步依賴的作用就是進行依賴的傳遞。spring-boot-starter-web分析源碼也是一樣,可自行查看
四、自動配置原理解析
按住Ctrl點擊查看啟動類MySpringBootApplication上的注解@SpringBootApplication
@SpringBootApplication public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class);} }@SpringBootApplication的源碼
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {..... }- @SpringBootConfiguration:等同與@Configuration,既標注該類是Spring的一個配置類
- @EnableAutoConfiguration:SpringBoot自動配置功能開啟
@EnableAutoConfiguration源碼
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {... ... ... }- @Import(AutoConfigurationImportSelector.class) 導入了AutoConfigurationImportSelector類
按住Ctrl點擊查看AutoConfigurationImportSelector源碼
@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}其中,**SpringFactoriesLoader.loadFactoryNames **方法的作用就是從META-INF/spring.factories文件中讀取指定類對應的類名稱列表
 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) //判斷你是否引入了相關依賴,引入依賴后該條件成立,當前類的配置才會生效 @ConditionalOnClass(ServletRequest.class) //滿足項目的類是是Type.SERVLET類型,也就是一個普通web工程 @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration {... ... ... }@EnableConfigurationProperties(ServerProperties.class) 代表加載ServerProperties服務器配置屬性類
進入ServerProperties.class源碼如下:
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties {/*** Server HTTP port.*/private Integer port;/*** Network address to which the server should bind.*/private InetAddress address;... ... ...}prefix = "server" 表示SpringBoot配置文件中的前綴,SpringBoot會將配置文件中以server開始的屬性映射到該類的字段中。
@ComponentScan
源碼翻譯:
配置組件掃描的指令。提供了類似與<context:component-scan>標簽的作用通過basePackageClasses或者basePackages屬性來指定要掃描的包。如果沒有指定這些屬性,那么將從聲明這個注解的類所在的包開始,掃描包及子包
而@SpringBootApplication注解聲明的類就是main函數所在的啟動類,因此掃描的包是該類所在包及其子包。因此,一般啟動類會放在一個比較前的包目錄中。
五、SpringBoot的配置文件
SpringBoot是基于約定的,所以很多配置都有默認值,但如果想使用自己的配置替換默認配置的話,就可以使用application.properties或者application.yml(application.yaml)進行配置。SpringBoot默認會從Resources目錄下加載application.properties或application.yml(application.yaml)文件。
application.yml配置文件
語法示例
普通數據:
- 語法: key: value
- 示例代碼:
- name: test
- 注意:value之前有一個空格
對象數據:
- 語法:
? key:
? key1: value1
? key2: value2
? 或者:
? key: {key1: value1,key2: value2} - 示例代碼:
- person:
name: test
age: 18
addr: shenzhen#或者
person: {name: test,age: 18,addr: shenzhen} - 注意:key1前面的空格個數不限定,在yml語法中,相同縮進代表同一個級別
Map數據 :
同上面的對象寫法
數組(List、Set)數據:
- 語法:
? key:
? - value1
? - value2
或者:
? key: [value1,value2] - 示例代碼:
- city:
- shenzhen
- shanghai
- shandong
- chongqing#或者
city: [shenzhen,shanghai,shandong,chongqing]#集合中的元素是對象形式
student:
- name: zhangsan
age: 18
score: 100
- name: lisi
age: 28
score: 88
- name: wangwu
age: 38
score: 90 - 注意:value1與之間的 - 之間存在一個空格
SpringBoot多環境配置
在實際開發的過程中,項目會經歷很多的階段(開發->測試->上線),每個階段的配置也會不同,例如:端口、上下文根、數據庫等,那么這個時候為了方便在不同的環境之間切換,SpringBoot提供了多環境配置,簡單示例如下:
application-dev.properties
#開發環境#設置內嵌Tomcat默認端口號 server.port=8080application-product.properties
#生產環境#配置內嵌Tomcat默認端口號 server.port=80application-test.properties
#測試環境#配置內嵌Tomcat端口號 server.port=8081● 在總配置文件application.properties進行環境的激活
#SpringBoot的總配置文件#激活開發環境 #spring.profiles.active=dev#激活測試環境 #spring.profiles.active=test#激活生產環境 spring.profiles.active=product六、 SpringBoot配置信息的查詢
SpringBoot的官方文檔:https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#common-application-properties
例如:
# EMBEDDED SERVER CONFIGURATION (ServerProperties) server.port=8080 # Server HTTP port. server.servlet.context-path= # Context path of the application. server.servlet.path=/ # Path of the main dispatcher servlet.那么可以通過配置application.poperties 或者 application.yml 來修改SpringBoot的默認配置
例如:
application.yml文件
server:port: 6666七、springboot讀取配置文件方式
@PropertySource配合@value使用
引入Druid連接池依賴:
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.6</version> </dependency>創建一個jdbc.properties文件,編寫jdbc屬性:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/test jdbc.username=root jdbc.password=root然后編寫代碼:
@Configuration @PropertySource("classpath:jdbc.properties") public class JdbcConfig {@Value("${jdbc.url}")String url;@Value("${jdbc.driverClassName}")String driverClassName;@Value("${jdbc.username}")String username;@Value("${jdbc.password}")String password;@Beanpublic DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(url);dataSource.setDriverClassName(driverClassName);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;} }解讀:
- @Configuration:聲明我們JdbcConfig是一個配置類
- @PropertySource:指定屬性文件的路徑是:classpath:jdbc.properties
若此例jdbc的屬性放在application.yml,那么可以不使用@PropertySource,@Value默認讀取; - 通過@Value為屬性注入值
- 通過@Bean將 dataSource()方法聲明為一個注冊Bean的方法,Spring會自動調用該方法,將方法的返回值加入Spring容器中。
@ConfigurationProperties使用
在上面的案例中,我們實驗了java配置方式。不過屬性注入使用的是@Value注解。這種方式雖然可行,但是不夠強大,因為它只能注入基本類型值。
在SpringBoot中,提供了一種新的屬性注入方式,支持各種java基本數據類型及復雜類型的注入。
新建一個類,用來進行屬性注入:
@ConfigurationProperties(prefix = "jdbc") public class JdbcProperties {private String url;private String driverClassName;private String username;private String password;// ... 略// getters 和 setters }- 在類上通過@ConfigurationProperties注解聲明當前類為屬性讀取類
- prefix="jdbc"讀取屬性文件中,前綴為jdbc的值。
- 在類上定義各個屬性,名稱必須與屬性文件中jdbc.后面部分一致
- 需要注意的是,這里并沒有指定屬性文件的地址,所以我們需要把jdbc.properties名稱改為application.properties,這是SpringBoot默認讀取的屬性文件名:
在JdbcConfig中使用這個屬性:
@Configuration @EnableConfigurationProperties(JdbcProperties.class) public class JdbcConfig {//@Autowired注入//private JdbcProperties prop;//構造函數注入//private JdbcProperties prop;//public JdbcConfig(Jdbcproperties prop){//this.prop = prop;}//聲明有@Bean的方法參數注入@Beanpublic DataSource dataSource(JdbcProperties jdbc) {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(jdbc.getUrl());dataSource.setDriverClassName(jdbc.getDriverClassName());dataSource.setUsername(jdbc.getUsername());dataSource.setPassword(jdbc.getPassword());return dataSource;} }- 通過@EnableConfigurationProperties(JdbcProperties.class)來聲明要使用JdbcProperties這個類的對象
- 然后使用@Autowired注入或構造函數注入或聲明有@Bean的方法參數注入
@ConfigurationProperties更優雅的注入
如果一些屬性只有一個Bean需要使用,那就無需將其注入到一個類(JdbcProperties)中。而是直接在需要的地方聲明即可:
@Configuration public class JdbcConfig {@Bean// 聲明要注入的屬性前綴,SpringBoot會自動把相關屬性通過set方法注入到DataSource中,前提是該類必須有對應屬性的set方法!@ConfigurationProperties(prefix = "jdbc")public DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();return dataSource;} }直接把@ConfigurationProperties(prefix = "jdbc")聲明在需要使用的@Bean的方法上,然后SpringBoot就會自動調用這個Bean(此處是DataSource)的set方法,然后完成注入。使用的前提是:該類必須有對應屬性的set方法!
八、SpringBoot事務管理
SpringBoot 使用事務非常簡單,底層依然采用的是Spring本身提供的事務管理
? 在入口類中使用注解 @EnableTransactionManagement 開啟事務支持
? 在訪問數據庫的Service方法上添加注解 @Transactional 即可
例如
@SpringBootApplication @EnableTransactionManagement //SpringBoot開啟事務的支持 public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}@Override @Transactional //添加此注解說明該方法添加的事務管理 public int update(Student student) {int updateCount = studentMapper.updateByPrimaryKeySelective(student);System.out.println("更新結果:" + updateCount);//在此構造一個除數為0的異常,測試事務是否起作用int a = 10/0;return updateCount; }九、SpringBoot打包方式
SpringBoot打war包部署
1.程序入口類需擴展繼承 SpringBootServletInitializer類并覆蓋configure方法(這是使用外置tomcat打包)
@SpringBootApplication public class Application extends SpringBootServletInitializer{public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { //參數為當前Spring Boot啟動類Application.classreturn builder.sources(Application.class);} }2.在 pom.xml中添加(修改)打包方式為war
<packaging>war</packaging>3.在 pom.xml中配置springboot打包的插件(默認自動加)
<!--SpringBoot 的打包插件--> <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId> </plugin>4.在pom.xml中配置將配置文件編譯到類路徑
<!--mybatis的mapper.xml--><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><!--src/main/resources下的所有配置文件編譯到classes下面去--><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource><resource><!--源文件位置--><directory>src/main/webapp</directory><!--編譯到META-INF/resources,該目錄不能隨便寫--><targetPath>META-INF/resources</targetPath><includes><!--要把哪些文件編譯過去,**表示webapp目錄及子目錄,*.*表示所有--><include>**/*.*</include></includes></resource>5.在pom.xml的build標簽下通過finalName指定打war包的名字
<!--指定打war包的名字--> <finalName>JavaDemo-springboot-war</finalName>6.通過Maven package命令打war包到target目錄下
7、將target目錄下生成的war包拷貝到tomcat的webapps目錄,并啟動tomcat,大功告成!
SpringBoot打Jar包部署
1.在 pom.xml中添加(修改)打包方式為war
<packaging>war</packaging>2.在 pom.xml中配置springboot打包的插件(默認自動加)
<!--SpringBoot 的打包插件--> <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId> </plugin>3、通過maven- package命令打包
4、通過java -jar jar包名稱命令運行
十、定時任務@Scheduled注解使用
cron表達式語法
[秒] [分] [小時] [日] [月] [周] [年]
注:[年]不是必須的域,可以省略[年],則一共6個域通配符說明:
- * 表示所有值。 例如:在分的字段上設置 *,表示每一分鐘都會觸發。
- ? 表示不指定值。使用的場景為不需要關心當前設置這個字段的值。例如:要在每月的10號觸發一個操作,但不關心是周幾,所以需要周位置的那個字段設置為”?” 具體設置為 0 0 0 10 * ?
- - 表示區間。例如 在小時上設置 “10-12”,表示 10,11,12點都會觸發。
- , 表示指定多個值,例如在周字段上設置 “MON,WED,FRI” 表示周一,周三和周五觸發
- / 用于遞增觸發。如在秒上面設置”5/15” 表示從5秒開始,每增15秒觸發(5,20,35,50)。 在月字段上設置’1/3’所示每月1號開始,每隔三天觸發一次。
- L 表示最后的意思。在日字段設置上,表示當月的最后一天(依據當前月份,如果是二月還會依據是否是潤年[leap]), 在周字段上表示星期六,相當于”7”或”SAT”。如果在”L”前加上數字,則表示該數據的最后一個。例如在周字段上設置”6L”這樣的格式,則表示“本月最后一個星期五”
- W 表示離指定日期的最近那個工作日(周一至周五). 例如在日字段上置”15W”,表示離每月15號最近的那個工作日觸發。如果15號正好是周六,則找最近的周五(14號)觸發, 如果15號是周未,則找最近的下周一(16號)觸發.如果15號正好在工作日(周一至周五),則就在該天觸發。如果指定格式為 “1W”,它則表示每月1號往后最近的工作日觸發。如果1號正是周六,則將在3號下周一觸發。(注,”W”前只能設置具體的數字,不允許區間”-“)。
- # 序號(表示每月的第幾個周幾),例如在周字段上設置”6#3”表示在每月的第三個周六.注意如果指定”#5”,正好第五周沒有周六,則不會觸發該配置(用在母親節和父親節再合適不過了) ;小提示:’L’和 ‘W’可以一組合使用。如果在日字段上設置”LW”,則表示在本月的最后一個工作日觸發;周字段的設置,若使用英文字母是不區分大小寫的,即MON與mon相同。
示例
在啟動類開啟計劃任務
@EnableScheduling//開啟計劃任務 表達式參考http://cron.qqe2.com/ public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}服務類
//@PostConstruct該注解被用來修飾一個非靜態的void()方法。被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,并且只會被服務器執行一次。PostConstruct在構造函數之后執行,init()方法之前執行。 //該注解的方法在整個Bean初始化中的執行順序: //Constructor(構造方法) -> @Autowired(依賴注入) -> @PostConstruct(注釋的方法)@PostConstruct@Overridepublic void init() {initAccessToken();}/*** 初始化AccessToken 一小時執行一次*/@Scheduled(cron = "0 0 0/1 * * ?")@Overridepublic void initAccessToken() {log.error("<====初始化 AccessToken 一分鐘一次 !==>");try {WxParament.ACCESS_TOKEN = GetToken.getAccessToken(ymlParament.getH_app_id(), ymlParament.getH_app_secret());} catch (Exception e) {log.error("<====initAccessToken初始化失敗!==>" + e);e.printStackTrace();}log.info("<====初始化initAccessToken成功,值為==>" + WxParament.ACCESS_TOKEN);}總結
以上是生活随笔為你收集整理的springboot starter工作原理_springboot基础知识集结,你get到了吗的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 孩子往上翻眼睛是什么原因
- 下一篇: bp神经网络代码_精通数据科学笔记 神经