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注解声明一个建言,此建言直接使用拦截规则做为参数。