上篇文章介绍了Spring Boot的Demo教程:SpringBoot(一):初章,方便你们快速入门、了解、实践Spring Boot的特性;html
本章则继续介绍Spring Boot的其它特性java
上篇说过,咱们经过IDEA新建一个Project后,系统会帮咱们建立一个名为 artifactId + Application 的入口类,这个类有一个标准的Java应用程序的入口方法,而且类上标注@SpringBootApplication的注解。web
@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 { ...... }
咱们能够看到,@SpringBootApplication注解,其本质就是@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解组合而成spring
1. @SpringBootConfiguration实质上就是Spring的@Configuration注解,代表这个类是一个JavaConfig类、配置类数据库
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
2. @EnableAutoConfiguration注解的做用:基于导入的jar包依赖,使得SpringBoot去“猜想”你想要如何配置Spring。假设您的项目导入了spring-boot-starter-web的依赖(其依赖了Tomcat和SpringMVC等),则SpringBoot将自动假设您在开发一个WEB应用程序而且自动添加相应的spring配置。虽然“自动配置“被设计用来和“starter”一块儿工做,可是两者的概念并不直接相关,您能够自由挑选任意的starter依赖项以外的jar包,SpringBoot会尽力自动配置您的应用程序。其实@Enable*注解并非新发明的注解,在Spring 3 Framework以后的版本均可以找到它的身影,其目的是用这些注释替代传统XML配置文件。例如@EnableTransactionManagement(声明事务管理)、@EnableWebMvc(启用MVC)、@EnableCaching(启用缓存)、@EnableScheduling(初始化调度器)等。@EnableAutoConfiguration的理念和方式与这些注解一脉相承,简单归纳一下就是:借助@Import和AutoConfigurationImportSelector类的支持,收集和注册特定场景相关的bean定义bootstrap
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ...... }
3. @ComponentScan:告知Spring Framework,哪一个package下的某些注解标识过的类,会被Spring管理api
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { ...... }
对于Spring Boot来讲,有两种方式去配置咱们的项目,第一种即是使用经过application.yml或者application.properties。而第二种则是使用@Configuration注解和@Bean注解进行配置(这是后话)缓存
对于第一种配置方式,有两类配置文件:1)application.properties. 2)application.yml. 两类均可以配置Spring Boot项目中的一些参数设置、变量定义,咱们一般会在其中配置端口、数据库链接、cache链接等等,其实二者并没有本质区别,均是一种配置文件的写法,能够类比的想象传统Spring项目的XML和MyBatis的properties,都是配置文件的一种表达形式,区别仅在于直观与否、可读性、适用性等方面tomcat
application.properties(键值对一一对应,简单明了)安全
spring.application.name=demo
spring.profiles.active=dev
application.yml(自然的树形结构,一目了然)
spring:
application:
name: demo
profiles:
active: dev
TIP:
必定要注意,yml文件每个冒号后,都是有跟随着一个空格的,而且每个缩进都是两个空格(千万千万)
Other:
1. 配置文件的路径
此列表是按照优先级排序(列表中位置较高的路径下的配置文件中定义的属性将覆盖位置较低配置文件中的同名属性定义)
2. 如何修改默认的配置文件路径或名称
方法一(代码形式)
@SpringBootApplication public class DemoApplication { public static void main(String[] args) throws IOException { // SpringApplication.run(DemoApplication.class, args); // 读取配置文件 InputStream in = DemoApplication.class.getClassLoader().getResourceAsStream("xxx.properties"); Properties prop = new Properties(); prop.load(in); // 加载配置文件 SpringApplication application = new SpringApplication(DemoApplication.class); application.setDefaultProperties(prop); // 运行服务 application.run(); } }
方法二(启动时命令行参数形式)
使用环境属性切换名称或者路径(应用程序上下文须要根据配置文件决定具体加载内容,因此必须定义为environment属性)
java --jar xxx.jar --spring.config.name=xxx.properties
java --jar xxx.jar --spring.config.location=classpath:/xxx.properties
3. 相信你们在以后的学习中,也会有机会见到bootstrap.yml(bootstrap.application),它与application.yml(application.properties)的区别在于:前者在后者以前被加载并使用,主要用于引导后续的应用程序的上下文加载。例如在Spring Cloud Config Server(远程读取配置文件的一种解决方案)中先于应用程序上下文加载以前指定程序读取的配置文件的 url 以及一些加解密信息,这里再也不细述,等写Spring Cloud的随笔时,会从源码阶段对其进行分析。
在开发中,咱们常常须要自定义一些配置文件(例如JDBC链接等),在SpringBoot中应该如何使用呢?
1. 使用@Value注解读取配置文件(${key})
application.properties或任意能够被加载的配置文件
user.age=18 user.gender=男
代码
@RestController
public class DemoController { @Value("${user.name}") private String name; @Value("${user.age}") private Integer age; @Value("${user.gender}") private String gender; @RequestMapping("/hello") public String hello() { return "{name:" + name + ", age:" + age + ", gender:" + gender + "}"; } }
地址栏访问后却发现一件很诡异的事情,中文竟然乱码了,而且项目也是默认指定了UTF-8
这是由于程序默认是以ISO-8859-1的字符编码读取配置文件的(另外,真的有人在配置文件中写中文吗 = = Orz)
解决方案
1.
# 设置 Spring Boot 编码格式
# 1.banner中文乱码问题(SpringBoot2.0以前的版本修改成banner.charset)
spring.banner.charset=UTF-8
# 2.返回页面、数据中文乱码问题
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
# 3.解决程序读配置文件乱码问题
spring.messages.encoding=UTF-8
2. (此步骤个人IDEA并无设置,读取也是正常的,可是很早以前学习Spring Boot时就碰见了此问题,粘贴出来供你们参考)
IDEA:
设置 File Encodings的Transparent native-to-ascii conversion为true,具体步骤以下:
依次点击
File -> Settings -> Editor -> File Encodings
将Properties Files (*.properties)下的Default encoding for properties files设置为UTF-8,将Transparent native-to-ascii conversion前的选项勾选上便可解决
Eclipse:
安装properties插件PropertiesEditor,对其进行设置,ASCII码转换成中文
2. JavaBean方式读取自定义properties(使用@ConfigurationProperties指定统一的前缀,@PropertySource注解指定配置文件路径)(有时候属性太多了,一个个绑定到属性字段上太累,并且官方提倡绑定一个对象的bean)
user.properties
user.age=18 user.gender=男
代码
@Configuration
@ConfigurationProperties(prefix = "user")
@PropertySource("classpath:user.properties")
public class UserEntity {
private Integer age;
private String gender;
......
}
@RestController
public class DemoController {
@Autowired
private UserEntity user;
@RequestMapping("/hello")
public String hello() {
return "{age:" + user.getAge() + ", gender:" + user.getGender() + "}";
}
}
在配置文件中,各个参数之间能够直接引用,就像下面的设置
user.age=18 user.gender=男 user.info=${user.age}, ${user.gender}
# 随机字符串 com.wangyanrui.value=${random.value} # 随机int com.wangyanrui.randomInt=${random.int} # 随机long com.wangyanrui.randomLong=${random.long} # 随机uuid com.wangyanrui.randomUUID=${random.uuid} # 100之内的随机数 com.wangyanrui.randomRangeInt1=${random.int(100)} # 100到200之间的随机数 com.wangyanrui.randomRangeInt2=${random.int[100,200]}
相信对于WEB项目,不少人都有设置过服务端口的经历。在Spring Boot中,咱们能够在application.properties(yml)中设置,亦或者在启动时动态的输入启动参数,两者是等价的
在命令行中,两个连续“-”号后的内容(key=value)就是对application.properties中的属性值进行赋值
java -jar xxx.jar --server.port=10000
经过命令行修改属性当然提供了不错的便捷性,可是经过命令行就能够修改程序运行的参数,在某些状况下岂不是很不安全(萌新瑟瑟发抖),Spring Boot也为咱们提供了屏蔽命令行的设置
@SpringBootApplication public class DemoApplication { public static void main(String[] args) throws IOException { // SpringApplication.run(DemoApplication.class, args); SpringApplication application = new SpringApplication(DemoApplication.class); // 禁止命令行设置属性值 application.setAddCommandLineProperties(false); application.run(args); } }
咱们在开发Spring Boot项目时,一般同一套程序会被应用和安装到不一样的环境中,例如开发、测试、生产等。各个环境的数据库地址,服务器端口等等配置均会不一样,若是在每次发布程序时都要大批量的修改这部分数据,是一件极其极其繁琐且容易发生错误的事
对于多环境的配置,各个构建工具或者框架的基本思路是一致的,即经过配置多份不一样环境的配置文件,经过一些打包命令指定打包的内容加以区分。Spring Boot也不例外,或者说,相比较传统Maven来讲更加简单便捷
在Spring Boot的多环境配置中,配置文件的名称须要知足"application-{profile}.properties"或"application-{profile}.yml"的形式,其中"profile"对应了不一样的环境标识
至于哪一个具体的文件会被加载,须要在application.properties中,经过spring.profiles.active属性进行设置,其值对应了不一样的"{profile}"值
如:spring.profiles.active=prod,则指定加载application-prod.properties配置文件的内容
因此,Spring Boot配置多环境的思路以下
application.properties中配置通用内容,而且设置"spring.profiles.active=xxx"指定程序运行读取的配置文件
application-xxx.properties配置各个环境不一样的内容
经过修改application.properties或者命令行的形式,激活不一样环境的配置
SpringBoot内部日志系统使用Apache的Commons Logging对JDKLogging、Log4J2和Logback提供了默认配置,而且若是使用的“starters”,那么默认使用的就是Logback,咱们能够经过依赖关系看出默认的日志依赖为Logback
简而言之,只要你的POM文件中使用了spring-boot-starter(starter是SpringBoot的核心部件,不使用它,近乎于自残手脚= =),就表明其会自动配置Logback做为日志的实现
SpringBoot最招人喜欢的一大特色即是配置方便,关于日志配置的相关参数,只须要写在application.properties中就能够生效
对于日志来讲,application.properties仅仅只能作一些基本配置,仍是应该添加对应日志系统的配置文件的。我的建议,若是仅仅是本地演示或者非生产使用,SpringBoot对于Logback的默认配置就足够使用,咱们仍是要以配置文件的形式为主。这里不对application.properties配置日志和日志的基本概念作过多的描述,下面归纳了配置文件所能配置的所有选项,其中logging.config主要用于指定日志配置的文件路径(因为日志是在应用程序上下文被建立以前初始化,因此不能使用@Configuration和@PropertySource(value={"classpath:application.properties"})对其进行配置),其他配置项见名知意便可。
logging.config # 日志配置文件路径,如 classpath:logback-spring.xml
logging.exception-conversion-word # 记录异常时使用的转换词
logging.file # 记录日志的文件名称,如:dev.log
logging.file.max-history # 日志的文件自动切割时长
logging.file.max-size # 日志的文件自动切割大小(默认10MB)
logging.level.* # 日志映射,如:logging.level.root=WARN,logging.level.org.springframework.web=DEBUG
logging.path # 记录日志的文件路径,如:c:/
logging.pattern.console # 向控制台输出的日志格式,只支持默认的 logback 设置。
logging.pattern.dateformat # 向控制台输出的日期格式,只支持默认的 logback 设置。
logging.pattern.file # 向记录日志文件输出的日志格式,只支持默认的 logback 设置。
logging.pattern.level # 用于呈现日志级别的格式,只支持默认的 logback 设置。
logging.register-shutdown-hook # 初始化时为日志系统注册一个关闭钩子
Spring Boot默认加载classpath:logback-spring.xml、classpath:logback-spring.groovy、logback.xml、logback.groovy(咱们会尽能够的使用 "-spring" 的形式标注咱们的配置文件名称,SpringBoot会自动注入一些多环境的配置项,此对log4j2是无效的)(官方说log4j2也可使用"-spring",可是我发现并不生效)(咱们也能够自定义配置文件的名称,只须要在application.properties中经过logging.config指定日志文件路径便可)
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 文件输出格式 --> <property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n"/> <!-- test文件路径 --> <property name="TEST_FILE_PATH" value="c:/test.log"/> <!-- prod文件路径 --> <property name="PRO_FILE_PATH" value="/home/wangyanrui/logs"/> <!-- 开发环境 --> <springProfile name="dev"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${PATTERN}</pattern> </encoder> </appender> <root level="info"> <appender-ref ref="CONSOLE"/> </root> </springProfile> <!-- 测试环境 --> <springProfile name="test"> <!-- 天天产生一个文件 --> <appender name="TEST_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 文件路径 --> <file>${TEST_FILE_PATH}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 文件名称 --> <fileNamePattern>${TEST_FILE_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 文件最大保存历史数量 --> <MaxHistory>100</MaxHistory> </rollingPolicy> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>${PATTERN}</pattern> </layout> </appender> <root level="info"> <appender-ref ref="TEST_FILE"/> </root> </springProfile> <!-- 生产环境 --> <springProfile name="prod"> <appender name="PROD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${PRO_FILE_PATH}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${PRO_FILE_PATH}/warn.%d{yyyy-MM-dd}.log</fileNamePattern> <MaxHistory>100</MaxHistory> </rollingPolicy> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>${PATTERN}</pattern> </layout> </appender> <root level="warn"> <appender-ref ref="PROD_FILE"/> </root> </springProfile> </configuration>
其中,springProfile标签的name属性对应于application.properties中的spring.profiles.active。咱们能够经过指定不一样的profile,激活同一个日志配置文件中不一样springProfile标签下的配置内容
首先排除默认的Logback
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency>
引入基于SpringBoot的Log4j2 Starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
使用配置文件配置log4j2(关于多环境的log4j2,须要新建多个不一样的配置文件,在不一样的application-xxx.properties中分别指定不一样的配置文件便可)(官方说可使用"-spring",可是我发现并不生效)
<?xml version="1.0" encoding="UTF-8"?> <!--设置log4j2的自身log级别为warn --> <configuration status="warn"> <properties> <Property name="app_name">SpringBoot-demo</Property> <Property name="log_path">logs/${app_name}</Property> </properties> <appenders> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="[%d][%t][%p][%l] %m%n"/> </console> <RollingFile name="RollingFileInfo" fileName="${log_path}/info.log" filePattern="${log_path}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz"> <Filters> <ThresholdFilter level="INFO"/> <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/> </Filters> <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/> <Policies> <!-- 归档天天的文件 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 限制单个文件大小 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- 限制天天文件个数 --> <DefaultRolloverStrategy compressionLevel="0" max="10"/> </RollingFile> <RollingFile name="RollingFileWarn" fileName="${log_path}/warn.log" filePattern="${log_path}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz"> <Filters> <ThresholdFilter level="WARN"/> <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/> </Filters> <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/> <Policies> <!-- 归档天天的文件 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 限制单个文件大小 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- 限制天天文件个数 --> <DefaultRolloverStrategy compressionLevel="0" max="10"/> </RollingFile> <RollingFile name="RollingFileError" fileName="${log_path}/error.log" filePattern="${log_path}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz"> <ThresholdFilter level="ERROR"/> <PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n"/> <Policies> <!-- 归档天天的文件 --> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 限制单个文件大小 --> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- 限制天天文件个数 --> <DefaultRolloverStrategy compressionLevel="0" max="10"/> </RollingFile> </appenders> <loggers> <!--过滤掉spring和hibernate的一些无用的debug信息 --> <root level="info"> <appender-ref ref="Console"/> <appender-ref ref="RollingFileInfo"/> <appender-ref ref="RollingFileWarn"/> <appender-ref ref="RollingFileError"/> </root> </loggers> </configuration>
在POM.xml里设置
<packaging>war</packaging>
POM.xml中的spring-boot-starter-web默认引入了一个嵌入的Tomcat容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency>
@SpringBootApplication public class DemoApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // return super.configure(builder); return builder.sources(DemoApplication.class); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
命令行执行mvn的打包命令:mvn clean package便可
等待打包完成,将target目录下的war包放置在tomcat的webapps目录下,启动tomcat便可
热启动在正常开发项目中很常见,SpringBoot对其有很好的配置,只需修改POM.xml文件,添加以下内容便可支持热启动
dependency节点下添加以下依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> build节点的plugins节点修改成以下 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build>
这种方式是基于类热加载机制来实现热加载的,所以就要求了修改完成代码后必须从新编译当前代码后才能出发热部署。
Eclipse默认就支持自动编译,而在IDEA中默认是关闭了自动编译的,须要以下设置
1. 开启IDEA项目自动编译
设置 —> Build, Execut, Deployment —> Compiler,勾选中左侧的Build Project automatically
2. 开启IDEA项目自动make
ctrl + shift + a —> 搜索命令registry —> 勾选compiler.automake.allow.when.app.running
SringBoot的特性有不少,这里仅作简单的阐述,更多内容仍是推荐去看Spring爸爸的官方文档(PS:Spring的官方文档是我看到过的文档中描述最清楚的一个......)