Spring Boot 核心

Spring Boot的基本配置

一. 配置不繼承SpringBoot父依賴項目

在真實的企業級項目中,一個大的項目會由多個子模塊組成,每一個模塊是一個小的項目,那麼每一個模塊都有本身的父項目,這個時候就不能再依賴spring提供的父項目了,這時候怎麼辦呢?spring boot已經考慮到了這種可能性,下面就來看看怎麼解決的。
單一模塊的時候,咱們會看到咱們的Spring Boot項目有個parent依賴,以下所示:html

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.5.RELEASE</version>
        <relativePath />
    </parent>

在真實的企業級項目中,這部份內容被咱們本身的父模塊佔用了,好比變成了以下:java

<parent>
        <groupId>org.light4j</groupId>
        <artifactId>springBoot-basic</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

這個時候,只須要加以下依賴便可解決原來依賴Spring Bootparent的問題:git

<dependencyManagement>
        <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>1.4.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

別的部分不須要變更,後面的內容都按照這種方式來進行。github

二. 入口類和@SpringBootApplication

Spring Boot一般有一個名爲*Application的入口類,入口類裏面有一個main方法,這個main方法其實就是一個標準的Java應用的入口。在main方法中使用SpringApplication.run(HelloApplication.class, args),啓動Spring Boot應用項目。web

@SpringBootApplicationSpring Boot的核心註解,它是一個組合註解,對組合註解不瞭解的朋友能夠看前面的文章Spring4.x高級話題(五):組合註解與元註解SpringBootApplication源碼以下:redis

@Target({java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication
{
  public abstract Class<?>[] exclude();

  public abstract String[] excludeName();
}

@SpringBootApplication註解主要組合了@Configuration@EnableAutoConfiguration@ComponentScan;若不使用@SpringBootApplication註解,則能夠在入口類上直接使用@Configuration@EnableAutoConfiguration@ComponentScan三個註解的效果是同樣的。
其中@EnableAutoConfigurationSpring Boot根據類路徑中的jar包依賴爲當前項目進行自動配置。spring

例如,添加了spring-boot-starter-web依賴,會自動添加TomcatSpring MVC的依賴,那麼Spring Boot會對TomcatSpring MVC進行自動配置。mongodb

又如,添加了spring-boot-starter-jpa依賴,Spring Boot會自動進行JPA相關的配置。shell

Spring Boot會自動掃描@SpringBootApplication所在類的同級包(如org.light4j.springboot.config)以及下級包裏面的Bean(若爲JPA項目還能夠掃描標註@Entity的實體類)。建議入口類放置在groupId+arctifactID組合的包名下。數據庫

三. 關閉特定的自動配置

經過上面的@SpringBootApplication的源碼能夠看出,關閉特定的自動配置應該使用@SpringBootApplication註解的exclude參數,好比要關閉Spring Boot對數據源的自動配置,則能夠這樣使用,例如:

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})

四. 定製Banner

1. 修改Banner

Spring Boot啓動的時候會有一個默認啓動方案,以下圖所示:

若是想把這個圖案修改爲本身的,步驟以下所示:

(1). 在src/main/resources下新建一個banner.txt
(2). 經過http://patorjk.com/software/taag網站生成字符,如敲入的爲"fffff",將網站生成的字符複製到banner.txt中。
(3). 這時再啓動程序,圖案將變爲以下圖所示:

五. 關閉banner

1. 入口類main方法裏的內容修改成:

SpringApplication application = new SpringApplication(HelloApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);

2. 或者使用fluent API修改成:

new SpringApplicationBuilder(HelloApplication.class).bannerMode(Banner.Mode.OFF).run(args);

Spring Boot的配置文件

Spring Boot的全局配置文件的做用是對一些默認配置的配置值進行修改。Spring Boot使用一個全局的配置文件application.propertiesapplication.yml進行全局配置,放置在src/main/resources目錄或者類路徑的/config下。

Spring Boot不只支持常規的properties配置文件,還支持yaml語言的配置文件。yaml是以數據爲中心的語言,在配置數據的時候具備面向對象的特徵。

二. 簡單示例

Tomcat的默認端口號修改成9090,並將默認的訪問路徑」/」修改成」/springboot_configFile「,能夠在application.properties中添加:

server.port=9090
server.context-path=/springboot_configFile

或者在application.yml中添加:

server:
  port:9090
  contextPath:/springboot_configFile

從上面的配置能夠看出,在Spring Boot中,context-path,contextPath或者CONTEXT_PATH形式實際上是相通的。而且,yaml的配置更簡潔清晰,更多Spring Boot經常使用配置請參考官網文檔

Spring Boot的starter pom

Spring Boot經過使用starter pom使得咱們不須要關注各類依賴庫的處理,不須要具體的配置信息,由SpringBoot自動經過classpath路徑下的類發現須要的Bean,並織入bean

Spring Boot爲咱們提供了簡化企業級開發絕大多數場景的starter pom,只要使用了應用場景所須要的starter pom,相關的技術配置將會消除,就能夠獲得Spring Boot爲咱們提供的自動配置的Bean

官方提供的starter pom特別多,詳細可參考官網文檔。下面列出部分供參考:

名稱 描述
spring-boot-starter Spring Boot核心的starter,包含自動配置,日誌,yaml配置文件等的支持
spring-boot-starter-actuator 準生產應用,用來監控和管理應用
spring-boot-starter-remote-shell 提供基於ssh協議的監控和管理
spring-boot-starter-amqp 使用spring-rabbit來支持AMQP
spring-boot-starter-aop 使用spring-aop和AspectJ支持面向切面編程
spring-boot-starter-batch 提供對Spring Batch的支持
spring-boot-starter-cache 提供對Spring Cache的支持
spring-boot-starter-cloud-connectors 對雲平臺(Cloud Foundry,Heroku)提供的服務提供簡化的鏈接方式
spring-boot-starter-data-elasticsearch 經過spring-data-elasticsearch對Elasticsearcht提供支持
spring-boot-starter-data-gemfire 經過spring-data-gemfire對GemFire提供支持
spring-boot-starter-data-jpa 對JPA的支持,包含spring-data-jpa,spring-orm和Hibernate
spring-boot-starter-data-mongodb 經過spring-data-mongodb對MongoDB提供支持
spring-boot-starter-data-rest 經過spring-data-rest-webmvc將Spring Data respository暴露爲Rest的服務
spring-boot-starter-data-solr 經過spring-data-rest-solr對Apache Solr數據檢索平臺的支持。
spring-boot-starter-freemarker 對FreeMarker模板引擎提供支持
spring-boot-starter-groovy-templates 對Groovy模板引擎提供支持
spring-boot-starter-hateoas 經過spring-hateoas對基於HATEOAS的REST形式的網絡服務的支持
spring-boot-starter-hornetq 經過Hornetq對JMS的支持
spring-boot-starter-integration 對系統集成框架spring-integration的支持
spring-boot-starter-jdbc 對JDBC數據庫的支持
spring-boot-starter-jersey 對Jersery REST形式的網絡服務的支持
spring-boot-starter-jta-atomikos 經過Atomikos對分佈式事務的支持
spring-boot-starter-jta-bitronix 經過Bitronix對分佈式事務的支持
spring-boot-starter-mail 對javax.mail的支持
spring-boot-starter-mobile 對spring-mobile的支持
spring-boot-starter-mustache 對Mustache模板引擎的支持
spring-boot-starter-redis 對鍵值對內存數據庫Redis的支持,包含spring-redis
spring-boot-starter-security 對spring-security的支持
spring-boot-starter-social-facebook 經過spring-social-facebook對FaceBook的支持
spring-boot-starter-social-linkedin 經過spring-social-linkedin對LinkedIn的支持
spring-boot-starter-social-twitter 經過spring-social-twitter對Twitter的支持
spring-boot-starter-test 對經常使用的測試框架Junit,Hamcrest和Mockito的支持,包含spring-test模塊
spring-boot-starter-thymeleaf 對Thymeleaf模板引擎的支持,包含於Spring整合的配置
spring-boot-starter-velocity 對Velocity模板引擎的支持
spring-boot-starter-web 對Web項目開發的支持,包含Tomcat和spring-webmvc
spring-boot-starter-Tomcat Spring Boot默認的Servlet容器Tomcat
spring-boot-starter-Jetty 使用Jetty做爲Servlet容器替換Tomcat
spring-boot-starter-undertow 使用Undertow做爲Servlet容器替換Tomcat
spring-boot-starter-logging Spring Boot默認的日誌框架Logback
spring-boot-starter-log4j 支持使用log4J日誌框架
spring-boot-starter-websocket 對WebSocket開發的支持
spring-boot-starter-ws 對Spring Web Services的支持

二. 第三方starter pom

除了官方starter pom外,還有第三方爲Spring Boot所寫的starter pom,以下圖所示:

 

名稱 地址
Handlebars https://github.com/allegro/handlebars-spring-boot-starter
Vaadin https://github.com/vaadin/spring/tree/master/vaadin-spring-boot-starter
Apache Camel https://github.com/apache/camel/tree/master/components/camel-spring-boot
WRO4J https://github.com/sbuettner/spring-boot-autoconfigure-wro4j
Spring Batch(高級用法) https://github.com/codecentric/spring-boot-starter-batch-web
HDIV https://github.com/hdiv/spring-boot-starter-hdiv
Jade Templates (Jadw4j) https://github.com/domix/spring-boot-starter-jade4j
Activiti https://github.com/Activiti/Activiti/tree/master/modules/activiti-spring-boot/spring-boot-starte

若是有須要咱們也能夠編寫本身的starter pom

Spring Boot的xml配置

Spring Boot提倡零配置,即無xml配置,可是在實際項目中,可能有一些特殊要求你必須使用xml配置,這時候能夠經過在配置類上面使用Spring提供的@ImportResource來在加載xml配置,例如:

@ImportResource(value = { "classpath:some-context.xml","classpath:another-context.xml" })

二. 示例

1. 新建包

新建兩個包:org.light4j.springboot.xml.scanorg.light4j.springboot.xml.noScan

2. 新建啓動類

新建Application.java啓動類,放到包org.light4j.springboot.xml.scan下,根據Spring Boot的掃描原則(掃描從根包到子包的原則),可以掃描到org.light4j.springboot.xml.scan以及它的子包,org.light4j.springboot.xml.noScan包以及子包則不能被掃描到,代碼以下:

package org.light4j.springboot.xml.scan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3. 新建Service類

新建ScanServiceNoScanService兩個Service類,根據Spring Boot的掃描原則,咱們把ScanService寫在Spring Boot能夠掃描的位置,也即放到包org.light4j.springboot.xml.scan下,NoScanService寫在SpringBoot沒法掃描到的位置,也即放到包org.light4j.springboot.xml.noScan下。
ScanService.java代碼以下所示:

package org.light4j.springboot.xml.scan;

import org.springframework.stereotype.Service;

@Service
public class ScanService {
    public ScanService() {
        System.out.println("I am ScanService,i can be scan");
    }
}

NoScanService.java代碼以下所示:

package org.light4j.springboot.xml.noScan;

import org.springframework.stereotype.Service;

@Service
public class NoScanService {
    public NoScanService() {
        System.out.println("I am NoScanService,i can not be scan");
    }
}

4. 運行程序

運行Application.java,看到控制檯打印日誌以下圖所示:

從上面能夠看到,在程序啓動的時候,執行了ScanService類的構造函數,而NoScanService沒有執行,這是由於NoScanService所在的包沒有被掃描到,因此沒有進行初始化。 那麼下面咱們使用xml配置文件的方式進行引入。

5. 編寫application-bean.xml

src/main/resouces目錄下編寫配置文件application-bean.xml文件,內容以下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 注入spring boot沒法掃描到的bean. -->
    <bean id="noScanService" class="org.light4j.springboot.xml.noScan.NoScanService"></bean>

</beans>

6. 導入配置文件

在啓動類Application上使用註解@ImportResource(value = { "classpath:application-bean.xml" })導入bean的配置文件,修改後的Application啓動類以下圖所示:

package org.light4j.springboot.xml.scan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource(value = { "classpath:application-bean.xml" })
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

7.運行程序測試

運行Application.java,如今看到控制檯打印日誌以下圖所示:

從上面能夠看到,在程序啓動的時候,ScanServiceNoScanService的構造函數都被執行了,兩者構造函數裏的代碼都在控制檯打印。

命令行參數配置

Spring Boot能夠容許使用properties文件,yaml文件或者命令行參數做爲外部配置。使用properties文件,yaml文件進行配置的例子在以前文章Spring Boot核心(二):Spring Boot的配置文件中已經有過演示,下面專門說命令行參數配置。

Spring Boot能夠是基於jar包運行的,使用以下命令打包:

mvn package

打成jar包的程序能夠直接經過下面的命令運行:

java -jar xxx.jar

能夠經過如下命令修改Tomcat端口號:

java -jar xxx.jar --server.port=9090

修改以後Tomcat將在9090端口啓動服務。

常規屬性配置

在以前的文章Spring4.x經常使用配置(二):Spring EL和資源調用中講述了在常規Spring環境下,注入properties文件裏面的值的方式,經過@PropertySource指明properties文件的位置,而後經過@Value注入值。在Spring Boot裏,咱們只需在application.properties定義屬性,直接使用@Value注入值便可。

二. 示例

1. application.properties增長屬性:

article.author=feeerss
article.name=spring boot

2. 修改控制器類

控制器類以下所示:

package org.light4j.springboot.properties.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @Value("${article.author}")
    private String articleAuthor;
    @Value("${article.name}")
    private String articleName;

    @RequestMapping("/")
    public String hello() {
        return "article name is:" + articleName + " and article author is:" + articleName;
    }
}

3. 運行

啓動入口類Application,訪問http://localhost:8080/效果以下圖所示:

類型安全的屬性配置

常規屬性配置文章中使用@Value注入每一個配置在實際項目中會顯得格外麻煩,由於咱們的配置一般會是許多個,若使用上篇文章的方式則要使用@Value注入不少次。

Spring Boot還提供了基於類型安全的屬性配置方式,經過@ConfigurationPropertiesproperties屬性和一個Bean及其屬性關聯,從而實現類型安全的配置。

二. 示例

1. 新建Spring Boot項目

2.添加配置

application.properties上添加:

article.author=xxxxxxx
article.name=spring boot

固然,咱們也能夠新建一個properties文件,這就須要咱們在@ConfigurationProperties的屬性locations裏指定properties的位置,且須要在入口類上配置。

3. 建立類型安全的Bean,代碼以下所示:

package org.light4j.springboot.save.properties.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "article") // ①
public class ArticleSettings {
    private String author;
    private String name;
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

代碼解釋:

① 經過ConfigurationProperties加載properties文件內的配置,經過prefix屬性指定properties的配置的前綴,經過locations指定properties文件的位置,例如:

@ConfigurationProperties(prefix = "article",locations={"classpath:config/article.properties"})

本例中,因爲直接配置在application.properties文件裏面,因此不須要配置locations屬性。

4. 校驗代碼,修改HelloController的代碼以下所示:

package org.light4j.springboot.save.properties.controller;

import org.light4j.springboot.save.properties.config.ArticleSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Autowired
    private ArticleSettings articleSettings; //①

    @RequestMapping("/")
    public String hello() {
        return "article name is "+ articleSettings.getName()+" and article author is "+articleSettings.getAuthor();
    }
}

代碼解釋:

① 能夠用@Autowired直接注入該配置

日誌配置

Spring Boot支持Java Util LoggingLog4J,Log4J2Logback做爲日誌框架,不管使用哪一種日誌框架,SpringBoot已經爲當前使用的日誌框架在控制檯的輸出以及在文件的輸出作好了配置,能夠對比前面文章SpringMvc4.x基礎(一):Spring MVC項目快速搭建中沒有使用Spring Boot時候的日誌配置的方式。

默認狀況下,Spring Boot使用Logback做爲日誌框架。

二. 示例

1. 配置日誌文件,格式爲logging.file=文件路徑

logging.file=F:/mylog/log.log

2. 配置日誌級別,格式爲logging.level.包名=級別,以下所示:

logging.level.org.springframework.web = DEBUG

三. 測試

運行程序,能夠看到控制檯輸出DBUG日誌以下:

在文件路徑下生成了日誌文件,而且裏面也保存了日誌內容,以下圖所示:

Profile配置

ProfileSpring用來針對不一樣的環境對不一樣的配置提供支持的,全局Profile配置使用application-{profile}.properties(如application-prod.properties)。

經過在application.properties中設置spring.profiles.active的值來指定活動的Profile配置。

二. 示例

下面將進行一個最簡單的演示,例如咱們分別爲生產(prod)和開發(dev)環境,生產環境下端口號爲80,開發環境下端口號爲8888

1. 新建配置文件
src/main/resources下新建三個配置文件表明普通配置文件,開發環境配置文件,生產環境配置環境,文件名分別是application.propertiesapplication-dev.propertiesapplication-prod.properties

application-prod.properties文件的內容以下所示:

server.port=80

application-dev.properties文件的內容以下所示:

server.port=8888

此時src/main/resources的目錄結構以下所示:

2. 運行

application.properties增長內容:spring.profiles.active=dev啓動程序結果爲:
xxx
將文件application.properties的內容spring.profiles.active=dev修改成:spring.profiles.active=prod啓動程序結果爲:
xxx

關閉特定的自動配置:

如:@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })

啓動查看自動配置報告

在application.properties 增長debug=true

Spring Boot的AOP配置

AOPSpring框架中的一個重要內容,在Spring boot裏配置aop很是簡單,Spring BootAOP的默認配置屬性是開啓的,也就是說spring.aop.auto屬性的值默認是true,咱們只要引入了AOP依賴後,默認就已經增長了@EnableAspectJAutoProxy功能,不須要咱們在程序啓動類上面加入註解@EnableAspectJAutoProxy

下面將使用Spring Boot經過模擬記錄操做日誌來演示基於註解攔截的AOP實現方式。

二. 示例

1. 添加依賴

<!-- aop -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

2. 編寫攔截規則的註解

package org.light4j.springboot.aop.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {

    String value() default "";
}

(3). 在控制器的方法上使用註解@Action

package org.light4j.springboot.aop.controller;

import org.light4j.springboot.aop.annotation.Action;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/")
    @Action("hello")
    public String hello() {
        return "Hello Spring Boot";
    }
}

代碼解釋

@Action註解加在方法hello()上面。

(5). 編寫切面

package org.light4j.springboot.aop.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.light4j.springboot.aop.annotation.Action;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    // pointCut
    @Pointcut("@annotation(org.light4j.springboot.aop.annotation.Action)")
    public void log() {

    }

    /**
     * 前置通知
     */
    @Before("log()")
    public void doBeforeController(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Action action = method.getAnnotation(Action.class);
        System.out.println("action名稱 " + action.value()); // ⑤
    }

    /**
     * 後置通知
     */
    @AfterReturning(pointcut = "log()", returning = "retValue")
    public void doAfterController(JoinPoint joinPoint, Object retValue) {
        System.out.println("retValue is:" + retValue);
    }
}

代碼解釋

①經過@Aspect註解聲明該類是一個切面。
②經過@Component讓此切面成爲Spring容器管理的Bean
③經過@Pointcut註解聲明切面。
④經過@After註解聲明一個建言,並使用@Pointcut定義的切點。
⑤經過反射能夠得到註解上面的屬性,而後作日誌記錄相關的操做,下面的相同。
⑥經過@Before註解聲明一個建言,此建言直接使用攔截規則做爲參數。