- <strong>寫在前面</strong>
======
通過閱讀官方文檔以及編寫一些demo辈毯,個(gè)人認(rèn)為spring boot的核心思想是約定大于配置以及使用java配置代替xml配置湘换,簡化繁瑣的項(xiàng)目配置同時(shí)避免維護(hù)繁雜的xml文件午磁。 -
<strong>使用idea創(chuàng)建項(xiàng)目</strong>
======
這里創(chuàng)建一個(gè)web項(xiàng)目砚著,查看pom文件咳秉,spring boot默認(rèn)將項(xiàng)目打包成一個(gè)fat jar而不是war
<groupId>com.jd</groupId>
<artifactId>sblearn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
打包成可執(zhí)行jar需要引入spring boot的插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
項(xiàng)目配置可以繼承starter-parent,通常只需要指定parent的版本秉颗,其他需要的starter版本parent都會(huì)給出相應(yīng)的版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
啟動(dòng)一個(gè)spring boot web項(xiàng)目還需要依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
這里解釋一下starter痢毒,starter包含了需要的各種依賴也可以包含代碼以及配置的元數(shù)據(jù),由于有了starter蚕甥,我們使用的時(shí)候就無需再去添加各種依賴哪替,同時(shí)starter有許多默認(rèn)的配置,比如默認(rèn)使用內(nèi)置tomcat菇怀,默認(rèn)使用的端口號(hào)凭舶,默認(rèn)的上下文路徑,我們就無需再配置爱沟。
- <strong>認(rèn)識(shí)代碼和配置文件</strong>
======
項(xiàng)目的目錄如下所示:
項(xiàng)目創(chuàng)建過后帅霜,idea會(huì)生成一個(gè)spring boot啟動(dòng)類,啟動(dòng)類需要被@SpringBootApplication
注解呼伸,同時(shí)在main函數(shù)里面啟動(dòng)應(yīng)用(注:這是jar包的啟動(dòng)方式身冀,如果使用本地tomcat war包啟動(dòng),代碼有差別)括享。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SblearnApplication {
public static void main(String[] args) {
SpringApplication.run(SblearnApplication.class, args);
}
}
看一看@SpringBootApplication
搂根,該注解源代碼如下,注意Java doc最后一句奶浦,該注解等價(jià)于
@Configuration兄墅,@EnableAutoConfiguration,@ComponentScan
/**
* Indicates a {@link Configuration configuration} class that declares one or more
* {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
* auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
* annotation that is equivalent to declaring {@code @Configuration},
* {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 1.2.0
*/
@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
表明該注解是一個(gè)@configuration
注解的替代物澳叉,@configuration
注解的部分java doc如下,可以看出該注解是告訴spring容器可以讀取類里面被@Bean
注解的方法并生成相應(yīng)的bean沐悦。不難看出成洗,如果啟動(dòng)類里面不包含需要添加到容器的bean,那么@SpringBootConfiguration
可以省略
* Indicates that a class declares one or more {@link Bean @Bean} methods and
* may be processed by the Spring container to generate bean definitions and
* service requests for those beans at runtime, for example:
*
* <pre class="code">
* @Configuration
* public class AppConfig {
*
* @Bean
* public MyBean myBean() {
* // instantiate, configure and return bean ...
* }
* }
@EnableAutoConfiguration
則是告訴spring boot使用上下文自動(dòng)配置藏否,spring boot將會(huì)盡可能聰明的配置應(yīng)用需要的bean瓶殃。
@ComponentScan
則是掃描啟動(dòng)類路徑下所有的bean,因此啟動(dòng)類要放在類路徑最外層副签,保證所有bean都被掃描到遥椿。
再看resource目錄,分別包含static映射靜態(tài)資源淆储,templates包含模板文件冠场,以及項(xiàng)目配置屬性文件application.properties
,此時(shí)配置文件為空本砰。
此時(shí)web項(xiàng)目已經(jīng)可以啟動(dòng)碴裙,從這里至少可以看出,spring boot啟用了內(nèi)置tomcat幫我們完成配置,同時(shí)也不需要配置web.xml和spring mvc的一些基礎(chǔ)配置舔株,比如靜態(tài)資源路徑莺琳,mvc注解驅(qū)動(dòng)
<!-- 添加MVC注解模式 -->
<mvc:annotation-driven/>
<!-- 映射靜態(tài)資源 -->
<mvc:resources location="/WEB-INF/statics/" mapping="/resource/**"/>
此外還將resources目錄下的資源文件打包到了jar/war,不需要在pom里面另行配置载慈。
- <strong>spring boot的屬性配置</strong>
======
spring boot的屬性配置具有一定的優(yōu)先級(jí)別惭等,這里直接給出官方文檔的內(nèi)容:
1. home目錄下的devtools全局設(shè)置屬性( ~/.spring-bootdevtools.
properties ,如果devtools激活)办铡。
2. 測試用例上的@TestPropertySource注解辞做。
3. 測試用例上的@SpringBootTest#properties注解。
4. 命令行參數(shù)
5. 來自 SPRING_APPLICATION_JSON 的屬性(環(huán)境變量或系統(tǒng)屬性中內(nèi)嵌的內(nèi)聯(lián)
JSON)料扰。
6. ServletConfig 初始化參數(shù)凭豪。
7. ServletContext 初始化參數(shù)。
8. 來自于 java:comp/env 的JNDI屬性晒杈。
9. Java系統(tǒng)屬性(System.getProperties())嫂伞。
10. 操作系統(tǒng)環(huán)境變量。
11. RandomValuePropertySource拯钻,只包含 random.* 中的屬性帖努。
12. 沒有打進(jìn)jar包的Profile-specific應(yīng)用屬性( application-
{profile}.properties 和YAML變量)。
13. 打進(jìn)jar包中的Profile-specific應(yīng)用屬性( application-
{profile}.properties 和YAML變量)粪般。
14. 沒有打進(jìn)jar包的應(yīng)用配置( application.properties 和YAML變量)拼余。
15. 打進(jìn)jar包中的應(yīng)用配置( application.properties 和YAML變量)。
16. @Configuration 類上的 @PropertySource 注解亩歹。
17. 默認(rèn)屬性(使用 SpringApplication.setDefaultProperties 指定)匙监。
劃重點(diǎn),4在15小作,16確保了可以在命令行可以根據(jù)環(huán)境選擇哪一個(gè)配置文件以及特定的屬性配置亭姥。
spring boot支持yml文件進(jìn)行配置,個(gè)人比較支持這種新的方式顾稀,簡潔明了达罗。spring會(huì)加載application.yml,如果想要加載特定文件可以在application.yml里面提供如下配置:
#需要額外引入其他配置文件的時(shí)候可以通過spring.profiles.include=a,b静秆,其中a,b代表配置文件“-”后的部分粮揉,比如
#applicaition-important.yml,那么就應(yīng)該使用important
spring:
profiles:
active: dev
include: important,log
這里在項(xiàng)目中已經(jīng)存在application-dev.yml抚笔,application-important.yml扶认,以及application-log.yml。該配置表示要激活application-dev.yml(默認(rèn)是激活application-default.yml)塔沃,同時(shí)引入application-important.yml蝠引,application-log.yml阳谍。也可以在命令行通過--spring.profiles.active=dev來進(jìn)行激活。
3.1 <strong>yml的使用</strong>
yml文件采用key:value的形式螃概,比起properties文件更加簡潔和直觀矫夯,注意的是冒號(hào)后面需要一個(gè)空格。yml文件中可以引入已經(jīng)定義的屬性吊洼,如果是yml文件中的屬性通過${}引入训貌,如果是pom文件中的屬性則使用@@,如下:
production: dev
boot:
word: hey + ${production}
name: jason
env:
basic: @env.demo.basic@
<profiles>
<profile>
<id>all-env</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env.demo.basic>demo-basic-prop</env.demo.basic>
</properties>
</profile>
</profiles>
3-2 <strong>使用隨機(jī)值</strong>
spring boot可以使用random.*
為配置文件生成隨機(jī)值冒窍,這種方式利于測試
my:
secret: ${random.value}
number: ${random.int}
bignumber: ${random.long}
number.less.than.ten: ${random.int(10)}
number.in.range: ${random.int[1024,65536]}
使用規(guī)則是random.int*
語法是 OPEN value (,max) CLOSE 递沪,此處 OPEN,CLOSE 可以是任何字符综液,并且 value款慨,max 是整數(shù)。如果提供 max 谬莹,那么 value 是最小值檩奠, max 是最大值(不包含在內(nèi))。
3-3 <strong>屬性值的使用</strong>
項(xiàng)目中的屬性值都保存在上下文的enviroment中附帽,要使用屬性值有三種方式埠戳,第一種是使用@Value
進(jìn)行注入:
@Value("${env.basic}")
private String basicProp;
第二種是使用@ConfigurationProperties
通過在類或者方法上進(jìn)行注解,參數(shù)prefix表示屬性名的前綴蕉扮,spring將會(huì)盡可能的將以擁有該前綴的數(shù)值型注入到類和方法返回對(duì)象中整胃,下面注解到類上時(shí),boot.word以及boot.name
將可以注入到BootProperties
類的實(shí)例上面喳钟。@ConfigurationProperties
還可以和java提供的一些校驗(yàn)注解搭配使用屁使,比如@NotEmpty
@ConfigurationProperties(prefix = "boot")
@Component
public class BootProperties {
@NotEmpty
private String word;
@NotEmpty
private String name;
public String getWord() {
return word;
}
public BootProperties setWord(String word) {
this.word = word;
return this;
}
public String getName() {
return name;
}
public BootProperties setName(String name) {
this.name = name;
return this;
}
注解到方法上時(shí),屬性值將會(huì)注入到返回對(duì)象之中奔则,比如下面datasource的配置屋灌,只要在配置文件中寫好datasource相應(yīng)的屬性配置,@ConfigurationProperties
就可以完成自動(dòng)注入应狱。
@Bean("masterDataSource")
@Primary
@ConfigurationProperties(prefix = "masterDb.dataSource")
public DataSource getMasterDataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
//masterDataSourceProperties.setPropertyForDruid(druidDataSource);
return druidDataSource;
}
第三種方式是通過enviroment訪問,如下通過實(shí)現(xiàn)了ApplicationContextAware
接口祠丝,spring啟動(dòng)時(shí)將會(huì)調(diào)用setApplicationContext
方法獲取應(yīng)用上下文疾呻,應(yīng)用上下文可以訪問項(xiàng)目的各種屬性,包括java環(huán)境變量以及屬性文件中加入的屬性等
@Component
public class LocalApplicationContext implements ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static String getPropertyByName(String name){
return applicationContext.getEnvironment().getProperty(name);
}
public static <T> T getBeanByName(String beanName){
return (T) applicationContext.getBean(beanName);
}
public static <T> T getBeanByType(Class<T> type){
return applicationContext.getBean(type);
}
}
3-4 <strong>在代碼中引入配置文件</strong>
某些組件對(duì)spring boot的支持不夠好或者使用了自定義的一些xml標(biāo)簽写半,仍然需要通過xml文件進(jìn)行配置岸蜗,可以使用@ImportResource
注解,方式如下叠蝇,注意這里還需要使用@Configuration
注解璃岳,有了它spring才回去掃描這個(gè)類。這樣,jsf.xml中定義的bean都將注入到spring容器铃慷。
@Configuration
@ImportResource(locations = {"classpath:jsf.xml"})
public class AdditionalBeanConfig {
}
在代碼中也可以引入properties文件和yml文件单芜,這里需要注意的是sprint boot暫時(shí)還不支持通過注解引入yml文件,通過@PropertySources或者@PropertySource
都可以引入properties文件犁柜。
@Configuration
//@PropertySources({@PropertySource(""), @PropertySource("")})
@PropertySource("classpath:/important.properties")
public class ImportantProperty {
}
如果一定要通過代碼引入yml文件可以采用如下方式洲鸠,首先定義yml文件的初始化器
/**
* Created by admin360buyad on 2017-06-12.
* 通過實(shí)現(xiàn)ApplicationContextInitializer來添加其他的yml文件,不過這種方式硬編碼了
*/
public class YmlApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Resource resource = applicationContext.getResource(
"classpath:/important.yml");
YamlPropertySourceLoader yamlPropertySourceLoader = new YamlPropertySourceLoader();
try {
PropertySource<?> propertySource = yamlPropertySourceLoader
.load("importantyml", resource, null);
applicationContext.getEnvironment().getPropertySources()
.addLast(propertySource);
} catch (IOException e) {
e.printStackTrace();
}
}
}
接下來在應(yīng)用初始化時(shí)注冊(cè)到應(yīng)用
springApplication.addInitializers(new YmlApplicationContextInitializer());
不過以上兩種方式不推薦使用馋缅,因?yàn)橛簿幋a了扒腕。
3-5 <strong>使用@Profile決定加載時(shí)機(jī)</strong>
@Profile
可以作用到任何 的@Component 或 @Configuration
,使得他們只有在特定的配置文件被激活時(shí)才會(huì)被spring進(jìn)行處理萤悴。比如ProductionConfiguration
類只有當(dāng)spring.profiles.active=production
時(shí)才會(huì)被spring處理瘾腰。
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ...
}
- <strong>springapplication的啟動(dòng)</strong>
=========
一般情況下我們按照如下的方式啟動(dòng)springapplication,啟動(dòng)前我們可以設(shè)置一些相關(guān)的屬性覆履,比如是否啟用banner蹋盆,是否設(shè)置web環(huán)境以及添加特定的初始化器
@SpringBootApplication
public class SelfDefApplication{
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SelfDefApplication.class);
springApplication.setBannerMode(Banner.Mode.OFF);
//springApplication.setWebEnvironment(false);
//springApplication.addInitializers(new YmlApplicationContextInitializer());
springApplication.run(args);
//bootByBuilder(args);
}
我們看看構(gòu)造函數(shù)的代碼葡盗,通過java doc可以明白spring可以根據(jù)我們傳入的sources來加載相關(guān)的bean垒迂。
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param sources the bean sources
* @see #run(Object, String[])
* @see #SpringApplication(ResourceLoader, Object...)
*/
public SpringApplication(Object... sources) {
initialize(sources);
}
第二種方式是可以通過SpringApplicationBuilder
的流式API進(jìn)行創(chuàng)建蹋偏,實(shí)質(zhì)上底層都將調(diào)用SpringApplication
的構(gòu)造方法
public static void bootByBuilder(String[] args){
System.out.println("boot by builder");
new SpringApplicationBuilder(SelfDefApplication.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
前面兩種方式都是使用內(nèi)置的tomcat啟動(dòng)猎塞,我們可以通過配置文件或者自定義EmbeddedServletContainerCustomizer
來設(shè)置tomcat的參數(shù)控汉。
server:
port: 8082
@Configuration
public class CustomServletConfig {
@Bean
public EmbeddedServletContainerCustomizer getServletContainer(){
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
}
如果需要本地tomcat啟動(dòng)則需要繼承SpringBootServletInitializer
類跃赚,并且重寫configure
方法瞄摊,將啟動(dòng)類添加到SpringApplicationBuilder
的sources之中箱季。通過這種方式啟動(dòng)自定義的SpringApplication
類的main方法將不會(huì)得到執(zhí)行赂鲤。在代碼中或者配置文件中設(shè)置的tomcat屬性也會(huì)被自己配置的tomcat本身屬性覆蓋噪径。
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
builder.sources(this.getClass()).bannerMode(Banner.Mode.OFF);
return super.configure(builder);
}
除此之外我們需要在pom文件中排除tomcat的starter同時(shí)引入servlet的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--去掉內(nèi)置tomcat-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
如果想要在應(yīng)用啟動(dòng)后做一些事情有三種方法,第一種是往bean的構(gòu)造函數(shù)注入ApplicationArguments
数初,ApplicationArguments
是封裝了命令行啟動(dòng)參數(shù)的對(duì)象
@Component
public class ApplicationArgumentsBean {
@Autowired
public ApplicationArgumentsBean(ApplicationArguments applicationArguments){
Set<String> names = applicationArguments.getOptionNames();
for(String name : names){
System.out.println(name + ":" + applicationArguments.getOptionValues(name));
}
}
}
第二種方式是實(shí)現(xiàn)ApplicationRunner
接口
@Component
@Order(1)
public class ApplicationRunnerImple implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
Set<String> names = args.getOptionNames();
for(String name : names){
System.out.println(name + ":" + args.getOptionValues(name));
}
}
}
第三種方式是實(shí)現(xiàn)CommandLineRunner
接口找爱,@Order
會(huì)決定加載順序,與ApplicationRunner
接口不同的是泡孩,CommandLineRunner
的run方法參數(shù)是原始的命令行參數(shù)字符串
@Component
@Order(2)
public class CommandLineRunnerImpl implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("application has booted, the args is ");
for(String arg : args){
System.out.println(arg);
}
}
}
- <strong>使用Log4j2</strong>
=========
springboot默認(rèn)使用logback作為日志系統(tǒng)车摄,如果想要使用log4j2需要從starter中exclude掉logging部分,同時(shí)引入Log4j2的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--去掉boot自帶的日志系統(tǒng)使用Log4j-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<!--去掉內(nèi)置tomcat-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
去掉Logging的starter過后也去掉了springboot本身需要的日志jar包仑鸥,需要在pom中引入
<!--boot默認(rèn)的日志系統(tǒng)是這個(gè)吮播,去掉log的starter后需要重新引入-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
關(guān)于Log4j2的配置文件可以使用xml也可以使用yml,使用yml的時(shí)候需要額外的添加一個(gè)jar包依賴眼俊,這樣springboot才能解析yml中的配置
<!--解析log4j2.yml-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.8.8</version>
</dependency>
一個(gè)log4j2的簡單配置如下:
Configuration:
status: info
appenders:
Console:
name: STDOUT
PatternLayout:
Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
Loggers:
Root:
level: info
AppenderRef:
ref: STDOUT
如果我們想看springboot使用了哪些默認(rèn)配置意狠,將日志級(jí)別該為debug就可看到,這里給出一部分日志內(nèi)容:
Positive matches:
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
DataSourceAutoConfiguration#dataSourceInitializer matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer; SearchStrategy: all) did not find any beans (OnBeanCondition)
DataSourceConfiguration.Tomcat matched:
- @ConditionalOnClass found required class 'org.apache.tomcat.jdbc.pool.DataSource'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnProperty (spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource) matched (OnPropertyCondition)
DataSourcePoolMetadataProvidersConfiguration.TomcatDataSourcePoolMetadataProviderConfiguration matched:
- @ConditionalOnClass found required class 'org.apache.tomcat.jdbc.pool.DataSource'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
DataSourceTransactionManagerAutoConfiguration matched:
- @ConditionalOnClass found required classes 'org.springframework.jdbc.core.JdbcTemplate', 'org.springframework.transaction.PlatformTransactionManager'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
DataSourceTransactionManagerAutoConfiguration.DataSourceTransactionManagerConfiguration matched:
- @ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) found a primary bean from beans 'masterDataSource', 'clusterDataSource' (OnBeanCondition)
DefaultValidatorConfiguration#defaultValidator matched:
- @ConditionalOnMissingBean (types: javax.validation.Validator,org.springframework.validation.Validator; SearchStrategy: all) did not find any beans (OnBeanCondition)
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- DispatcherServlet Registration did not find servlet registration bean (DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition)
DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration matched:
- @ConditionalOnBean (names: dispatcherServlet; types: org.springframework.web.servlet.DispatcherServlet; SearchStrategy: all) found beans 'dispatcherServlet', 'dispatcherServlet' (OnBeanCondition)
EmbeddedServletContainerAutoConfiguration matched:
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
EmbeddedServletContainerAutoConfiguration.EmbeddedTomcat matched:
- @ConditionalOnClass found required classes 'javax.servlet.Servlet', 'org.apache.catalina.startup.Tomcat'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnMissingBean (types: org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; SearchStrategy: current) did not find any beans (OnBeanCondition)
ErrorMvcAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
ErrorMvcAutoConfiguration#basicErrorController matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.web.ErrorController; SearchStrategy: current) did not find any beans (OnBeanCondition)
ErrorMvcAutoConfiguration#errorAttributes matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.web.ErrorAttributes; SearchStrategy: current) did not find any beans (OnBeanCondition)
ErrorMvcAutoConfiguration.DefaultErrorViewResolverConfiguration#conventionErrorViewResolver matched:
- @ConditionalOnBean (types: org.springframework.web.servlet.DispatcherServlet; SearchStrategy: all) found bean 'dispatcherServlet'; @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.web.DefaultErrorViewResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)
ErrorMvcAutoConfiguration.WhitelabelErrorViewConfiguration matched:
- @ConditionalOnProperty (server.error.whitelabel.enabled) matched (OnPropertyCondition)
- ErrorTemplate Missing did not find error template view (ErrorMvcAutoConfiguration.ErrorTemplateMissingCondition)
ErrorMvcAutoConfiguration.WhitelabelErrorViewConfiguration#beanNameViewResolver matched:
- @ConditionalOnMissingBean (types: org.springframework.web.servlet.view.BeanNameViewResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)
ErrorMvcAutoConfiguration.WhitelabelErrorViewConfiguration#defaultErrorView matched:
- @ConditionalOnMissingBean (names: error; SearchStrategy: all) did not find any beans (OnBeanCondition)
GenericCacheConfiguration matched:
- Cache org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration automatic cache type (CacheCondition)
GuavaCacheConfiguration matched:
- @ConditionalOnClass found required classes 'com.google.common.cache.CacheBuilder', 'org.springframework.cache.guava.GuavaCacheManager'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- Cache org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration automatic cache type (CacheCondition)
HttpEncodingAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.filter.CharacterEncodingFilter'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
- @ConditionalOnProperty (spring.http.encoding.enabled) matched (OnPropertyCondition)
HttpEncodingAutoConfiguration#characterEncodingFilter matched:
- @ConditionalOnMissingBean (types: org.springframework.web.filter.CharacterEncodingFilter; SearchStrategy: all) did not find any beans (OnBeanCondition)
HttpMessageConvertersAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.converter.HttpMessageConverter'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
HttpMessageConvertersAutoConfiguration.StringHttpMessageConverterConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.converter.StringHttpMessageConverter'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
HttpMessageConvertersAutoConfiguration.StringHttpMessageConverterConfiguration#stringHttpMessageConverter matched:
- @ConditionalOnMissingBean (types: org.springframework.http.converter.StringHttpMessageConverter; SearchStrategy: all) did not find any beans (OnBeanCondition)
JacksonAutoConfiguration matched:
- @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
JacksonAutoConfiguration.Jackson2ObjectMapperBuilderCustomizerConfiguration matched:
- @ConditionalOnClass found required classes 'com.fasterxml.jackson.databind.ObjectMapper', 'org.springframework.http.converter.json.Jackson2ObjectMapperBuilder'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
JacksonAutoConfiguration.JacksonObjectMapperBuilderConfiguration matched:
- @ConditionalOnClass found required classes 'com.fasterxml.jackson.databind.ObjectMapper', 'org.springframework.http.converter.json.Jackson2ObjectMapperBuilder'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
JacksonAutoConfiguration.JacksonObjectMapperBuilderConfiguration#jacksonObjectMapperBuilder matched:
- @ConditionalOnMissingBean (types: org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; SearchStrategy: all) did not find any beans (OnBeanCondition)
JacksonAutoConfiguration.JacksonObjectMapperConfiguration matched:
- @ConditionalOnClass found required classes 'com.fasterxml.jackson.databind.ObjectMapper', 'org.springframework.http.converter.json.Jackson2ObjectMapperBuilder'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
JacksonAutoConfiguration.JacksonObjectMapperConfiguration#jacksonObjectMapper matched:
- @ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) did not find any beans (OnBeanCondition)
- <strong>配置Mybatis雙數(shù)據(jù)源</strong>
=========
這里數(shù)據(jù)源使用druid疮胖,數(shù)據(jù)庫使用mysql环戈,引入mybatis的starter闷板,pom配置如下:
<!--數(shù)據(jù)庫-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
為了使用雙數(shù)據(jù)源,在配置文件中我們?cè)O(shè)置兩套數(shù)據(jù)庫配置院塞,一套是master遮晚,一套是cluster,前綴分別使用masterDb.dataSource和clusterDb.dataSource迫悠,同時(shí)給出兩套不同的mybatis別名和mapper文件路徑的配置鹏漆。
masterDb:
dataSource:
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
mapperLocations: classpath:mapper/master/*.xml
typeAliasesPackage: com.example.domain.master
clusterDb:
dataSource:
url: jdbc:mysql://127.0.0.1:3306/seckill?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
mapperLocations: classpath:mapper/cluster/*.xml
typeAliasesPackage: com.example.domain.cluster
basePackage: com.example.dao.cluster
將配置引入到代碼中仍然是通過@Configuration
注解的配置類,第一點(diǎn)需要注意的是這里我們需要引入@MapperScan
注解创泄,給出dao層包的位置艺玲,mybatis會(huì)自動(dòng)實(shí)現(xiàn)該路徑下的所有接口,實(shí)現(xiàn)方式是根據(jù)類名與同名的mapper文件匹配鞠抑,將類里面的方法名和mapper文件內(nèi)的sql語句匹配并以此實(shí)現(xiàn)該接口饭聚,典型的約定大于配置哈!第二點(diǎn)是可以看出完成mybatis的配置需要數(shù)據(jù)源的配置搁拙,sessionfactory
的配置以及事務(wù)管理器的配置秒梳。第三點(diǎn)是增加@Primary
注解表明該數(shù)據(jù)源配置為最高優(yōu)先,在cluster的配置中不需要改注解箕速。第四點(diǎn)是注意使用不同的bean名稱酪碘。這樣我們已經(jīng)可以在一個(gè)應(yīng)用中使用兩套數(shù)據(jù)源配置了。
/**
* Created by admin360buyad on 2017-06-07.
* 多數(shù)據(jù)源配置盐茎,配置主數(shù)據(jù)源
* spring容器可以自動(dòng)識(shí)別哪些Bean需要先裝配兴垦,下面的代碼中,spring首先會(huì)注入masterDataSource
* 接下來才是masterSqlSessionFactory和masterDataSourceTm
*/
@Configuration
@MapperScan(basePackages = "com.example.dao.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDbConfig {
/**
* mybatis自動(dòng)掃描該包下的domain并且根據(jù)類名的首字母小寫設(shè)置別名
*/
@Value("masterDb.dataSource.typeAliasPackage")
private String typeAliasPackage;
/**
* mybatis mapper文件的地址
*/
@Value("masterDb.dataSource.mapperLocations")
private String mapperLocations;
@Bean("masterDataSource")
@Primary
@ConfigurationProperties(prefix = "masterDb.dataSource")
public DataSource getMasterDataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
//masterDataSourceProperties.setPropertyForDruid(druidDataSource);
return druidDataSource;
}
@Bean("masterSqlSessionFactory")
@Primary
public SqlSessionFactory getMasterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage(typeAliasPackage);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(mapperLocations));
return factoryBean.getObject();
}
@Bean("masterDataSourceTm")
@Primary
public DataSourceTransactionManager getTransactionManager(@Qualifier("masterDataSource") DataSource dataSource)
throws SQLException {
return new DataSourceTransactionManager(dataSource);
}
}
- <strong>配置velocity</strong>
=========
springboot的最新版本默認(rèn)已經(jīng)不支持velocity字柠,所以需要我們通過@Configuration自動(dòng)配置探越,首先引入velocity的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
接下來是配置類,我們需要提供VelocityViewResolver和VelocityConfigurer
兩個(gè)bean窑业。這里對(duì)VelocityViewResolver
使用了@Order(1)
表明spring mvc會(huì)嘗試首先使用該viewResolver
來返回請(qǐng)求(如果存在比1的值更低的order將具有更高優(yōu)先級(jí))钦幔,所有的viewResolver
都將被ContentNegotiatingViewResolver
管理,ContentNegotiatingViewResolver
本身不對(duì)請(qǐng)求處理常柄,只負(fù)責(zé)管理其他viewResolver
鲤氢,并且在其初始化時(shí)將獲取spring容器中所有的viewResolver
@Configuration
public class VelocityConfig {
@Bean("velocityViewResolver")
@Order(1)
public ViewResolver getViewResolver(){
VelocityViewResolver resolver = new VelocityViewResolver();
resolver.setSuffix(".vm");
return resolver;
}
@Bean("velocityConfigurer")
public VelocityConfigurer getVelocityConfigurer(){
VelocityConfigurer configurer = new VelocityConfigurer();
configurer.setResourceLoaderPath("classpath:/templates/");
configurer.setConfigLocation(new PathMatchingResourcePatternResolver()
.getResource("classpath:/properties/velocity.properties"));
return configurer;
}
}
- <strong>spring mvc的一些配置</strong>
=========
spring mvc靜態(tài)資源的配置可以寫在配置文件
resources:
static-locations: classpath:/statics/
mvc:
static-path-pattern: /resource/**
下載上傳的限制也可以
spring:
http:
multipart:
max-file-size: 2MB
spring boot提供了很多默認(rèn)的mvc配置,如果我們想要修改都可以通過在配置溫江中自己配置西潘。
- <strong>springboot測試</strong>
=========
一個(gè)簡單的spring boot測試代碼如下所示
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class DemoApplicationTests {
@Autowired
private HobbyDao hobbyDao;
@Test
public void contextLoads() {
}
@Test
public void testHobbyDao(){
System.out.println(JSON.toJSONString(hobbyDao.selectAllHobby()));
}
}
第一步通過@RunWith
配置SpringRunner
铜异,第二步則是通過@SpringBootTest
注解配置測試的啟動(dòng)信息,先看第一個(gè)參數(shù)classes秸架,其java doc如下,可以看出其作用是通過參數(shù)類加載一個(gè)spring的上下文咆蒿,如果改參數(shù)未指定將在該測試類內(nèi)部尋找可加載的配置類
/**
* The <em>annotated classes</em> to use for loading an
* {@link org.springframework.context.ApplicationContext ApplicationContext}. Can also
* be specified using
* {@link ContextConfiguration#classes() @ContextConfiguration(classes=...)}. If no
* explicit classes are defined the test will look for nested
* {@link Configuration @Configuration} classes, before falling back to a
* {@link SpringBootConfiguration} search.
* @see ContextConfiguration#classes()
* @return the annotated classes used to load the application context
*/
第二個(gè)參數(shù)是webEnvironment 东抹,java doc如下蚂子,意思是我們創(chuàng)建web環(huán)境的類型,默認(rèn)是一個(gè)mock缭黔,選項(xiàng)包括
/**
* Creates a {@link WebApplicationContext} with a mock servlet environment or a
* regular {@link ApplicationContext} if servlet APIs are not on the classpath.
*/
MOCK(false),
/**
* Creates an {@link EmbeddedWebApplicationContext} and sets a
* {@code server.port=0} {@link Environment} property (which usually triggers
* listening on a random port). Often used in conjunction with a
* {@link LocalServerPort} injected field on the test.
*/
RANDOM_PORT(true),
/**
* Creates an {@link EmbeddedWebApplicationContext} without defining any
* {@code server.port=0} {@link Environment} property.
*/
DEFINED_PORT(true),
/**
* Creates an {@link ApplicationContext} and sets
* {@link SpringApplication#setWebEnvironment(boolean)} to {@code false}.
*/
NONE(false);
該注解還包括如下兩個(gè)參數(shù)用于自定義一些需要使用的屬性配置
/**
* Alias for {@link #properties()}.
* @return the properties to apply
*/
@AliasFor("properties")
String[] value() default {};
/**
* Properties in form {@literal key=value} that should be added to the Spring
* {@link Environment} before the test runs.
* @return the properties to add
*/
@AliasFor("value")
String[] properties() default {};