spring boot项目搭建
- <strong>写在前面</strong>
======
通过阅读官方文档以及编写一些demo,个人认为spring boot的核心思想是约定大于配置以及使用java配置代替xml配置,简化繁琐的项目配置同时避免维护繁杂的xml文件。 -
<strong>使用idea创建项目</strong>
======
这里创建一个web项目,查看pom文件,spring boot默认将项目打包成一个fat jar而不是war
<groupId>com.jd</groupId>
<artifactId>sblearn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
打包成可执行jar需要引入spring boot的插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
项目配置可以继承starter-parent,通常只需要指定parent的版本,其他需要的starter版本parent都会给出相应的版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
启动一个spring boot web项目还需要依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
这里解释一下starter,starter包含了需要的各种依赖也可以包含代码以及配置的元数据,由于有了starter,我们使用的时候就无需再去添加各种依赖,同时starter有许多默认的配置,比如默认使用内置tomcat,默认使用的端口号,默认的上下文路径,我们就无需再配置。
- <strong>认识代码和配置文件</strong>
======
项目的目录如下所示:
项目创建过后,idea会生成一个spring boot启动类,启动类需要被@SpringBootApplication
注解,同时在main函数里面启动应用(注:这是jar包的启动方式,如果使用本地tomcat war包启动,代码有差别)。
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最后一句,该注解等价于
@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
表明该注解是一个@configuration
注解的替代物,@configuration
注解的部分java doc如下,可以看出该注解是告诉spring容器可以读取类里面被@Bean
注解的方法并生成相应的bean。不难看出,如果启动类里面不包含需要添加到容器的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使用上下文自动配置,spring boot将会尽可能聪明的配置应用需要的bean。
@ComponentScan
则是扫描启动类路径下所有的bean,因此启动类要放在类路径最外层,保证所有bean都被扫描到。
再看resource目录,分别包含static映射静态资源,templates包含模板文件,以及项目配置属性文件application.properties
,此时配置文件为空。
此时web项目已经可以启动,从这里至少可以看出,spring boot启用了内置tomcat帮我们完成配置,同时也不需要配置web.xml和spring mvc的一些基础配置,比如静态资源路径,mvc注解驱动
<!-- 添加MVC注解模式 -->
<mvc:annotation-driven/>
<!-- 映射静态资源 -->
<mvc:resources location="/WEB-INF/statics/" mapping="/resource/**"/>
此外还将resources目录下的资源文件打包到了jar/war,不需要在pom里面另行配置。
- <strong>spring boot的属性配置</strong>
======
spring boot的属性配置具有一定的优先级别,这里直接给出官方文档的内容:
1. home目录下的devtools全局设置属性( ~/.spring-bootdevtools.
properties ,如果devtools激活)。
2. 测试用例上的@TestPropertySource注解。
3. 测试用例上的@SpringBootTest#properties注解。
4. 命令行参数
5. 来自 SPRING_APPLICATION_JSON 的属性(环境变量或系统属性中内嵌的内联
JSON)。
6. ServletConfig 初始化参数。
7. ServletContext 初始化参数。
8. 来自于 java:comp/env 的JNDI属性。
9. Java系统属性(System.getProperties())。
10. 操作系统环境变量。
11. RandomValuePropertySource,只包含 random.* 中的属性。
12. 没有打进jar包的Profile-specific应用属性( application-
{profile}.properties 和YAML变量)。
13. 打进jar包中的Profile-specific应用属性( application-
{profile}.properties 和YAML变量)。
14. 没有打进jar包的应用配置( application.properties 和YAML变量)。
15. 打进jar包中的应用配置( application.properties 和YAML变量)。
16. @Configuration 类上的 @PropertySource 注解。
17. 默认属性(使用 SpringApplication.setDefaultProperties 指定)。
划重点,4在15,16确保了可以在命令行可以根据环境选择哪一个配置文件以及特定的属性配置。
spring boot支持yml文件进行配置,个人比较支持这种新的方式,简洁明了。spring会加载application.yml,如果想要加载特定文件可以在application.yml里面提供如下配置:
#需要额外引入其他配置文件的时候可以通过spring.profiles.include=a,b,其中a,b代表配置文件“-”后的部分,比如
#applicaition-important.yml,那么就应该使用important
spring:
profiles:
active: dev
include: important,log
这里在项目中已经存在application-dev.yml,application-important.yml,以及application-log.yml。该配置表示要激活application-dev.yml(默认是激活application-default.yml),同时引入application-important.yml,application-log.yml。也可以在命令行通过--spring.profiles.active=dev来进行激活。
3.1 <strong>yml的使用</strong>
yml文件采用key:value的形式,比起properties文件更加简洁和直观,注意的是冒号后面需要一个空格。yml文件中可以引入已经定义的属性,如果是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>使用随机值</strong>
spring boot可以使用random.*
为配置文件生成随机值,这种方式利于测试
my:
secret: ${random.value}
number: ${random.int}
bignumber: ${random.long}
number.less.than.ten: ${random.int(10)}
number.in.range: ${random.int[1024,65536]}
使用规则是random.int*
语法是 OPEN value (,max) CLOSE ,此处 OPEN,CLOSE 可以是任何字符,并且 value,max 是整数。如果提供 max ,那么 value 是最小值, max 是最大值(不包含在内)。
3-3 <strong>属性值的使用</strong>
项目中的属性值都保存在上下文的enviroment中,要使用属性值有三种方式,第一种是使用@Value
进行注入:
@Value("${env.basic}")
private String basicProp;
第二种是使用@ConfigurationProperties
通过在类或者方法上进行注解,参数prefix表示属性名的前缀,spring将会尽可能的将以拥有该前缀的数值型注入到类和方法返回对象中,下面注解到类上时,boot.word以及boot.name
将可以注入到BootProperties
类的实例上面。@ConfigurationProperties
还可以和java提供的一些校验注解搭配使用,比如@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;
}
注解到方法上时,属性值将会注入到返回对象之中,比如下面datasource的配置,只要在配置文件中写好datasource相应的属性配置,@ConfigurationProperties
就可以完成自动注入。
@Bean("masterDataSource")
@Primary
@ConfigurationProperties(prefix = "masterDb.dataSource")
public DataSource getMasterDataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
//masterDataSourceProperties.setPropertyForDruid(druidDataSource);
return druidDataSource;
}
第三种方式是通过enviroment访问,如下通过实现了ApplicationContextAware
接口,spring启动时将会调用setApplicationContext
方法获取应用上下文,应用上下文可以访问项目的各种属性,包括java环境变量以及属性文件中加入的属性等
@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>
某些组件对spring boot的支持不够好或者使用了自定义的一些xml标签,仍然需要通过xml文件进行配置,可以使用@ImportResource
注解,方式如下,注意这里还需要使用@Configuration
注解,有了它spring才回去扫描这个类。这样,jsf.xml中定义的bean都将注入到spring容器。
@Configuration
@ImportResource(locations = {"classpath:jsf.xml"})
public class AdditionalBeanConfig {
}
在代码中也可以引入properties文件和yml文件,这里需要注意的是sprint boot暂时还不支持通过注解引入yml文件,通过@PropertySources或者@PropertySource
都可以引入properties文件。
@Configuration
//@PropertySources({@PropertySource(""), @PropertySource("")})
@PropertySource("classpath:/important.properties")
public class ImportantProperty {
}
如果一定要通过代码引入yml文件可以采用如下方式,首先定义yml文件的初始化器
/**
* Created by admin360buyad on 2017-06-12.
* 通过实现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();
}
}
}
接下来在应用初始化时注册到应用
springApplication.addInitializers(new YmlApplicationContextInitializer());
不过以上两种方式不推荐使用,因为硬编码了。
3-5 <strong>使用@Profile决定加载时机</strong>
@Profile
可以作用到任何 的@Component 或 @Configuration
,使得他们只有在特定的配置文件被激活时才会被spring进行处理。比如ProductionConfiguration
类只有当spring.profiles.active=production
时才会被spring处理。
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ...
}
- <strong>springapplication的启动</strong>
=========
一般情况下我们按照如下的方式启动springapplication,启动前我们可以设置一些相关的属性,比如是否启用banner,是否设置web环境以及添加特定的初始化器
@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);
}
我们看看构造函数的代码,通过java doc可以明白spring可以根据我们传入的sources来加载相关的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进行创建,实质上底层都将调用SpringApplication
的构造方法
public static void bootByBuilder(String[] args){
System.out.println("boot by builder");
new SpringApplicationBuilder(SelfDefApplication.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
前面两种方式都是使用内置的tomcat启动,我们可以通过配置文件或者自定义EmbeddedServletContainerCustomizer
来设置tomcat的参数。
server:
port: 8082
@Configuration
public class CustomServletConfig {
@Bean
public EmbeddedServletContainerCustomizer getServletContainer(){
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
}
如果需要本地tomcat启动则需要继承SpringBootServletInitializer
类,并且重写configure
方法,将启动类添加到SpringApplicationBuilder
的sources之中。通过这种方式启动自定义的SpringApplication
类的main方法将不会得到执行。在代码中或者配置文件中设置的tomcat属性也会被自己配置的tomcat本身属性覆盖。
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
builder.sources(this.getClass()).bannerMode(Banner.Mode.OFF);
return super.configure(builder);
}
除此之外我们需要在pom文件中排除tomcat的starter同时引入servlet的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--去掉内置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>
如果想要在应用启动后做一些事情有三种方法,第一种是往bean的构造函数注入ApplicationArguments
,ApplicationArguments
是封装了命令行启动参数的对象
@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));
}
}
}
第二种方式是实现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));
}
}
}
第三种方式是实现CommandLineRunner
接口,@Order
会决定加载顺序,与ApplicationRunner
接口不同的是,CommandLineRunner
的run方法参数是原始的命令行参数字符串
@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默认使用logback作为日志系统,如果想要使用log4j2需要从starter中exclude掉logging部分,同时引入Log4j2的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--去掉boot自带的日志系统使用Log4j-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<!--去掉内置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默认的日志系统是这个,去掉log的starter后需要重新引入-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
关于Log4j2的配置文件可以使用xml也可以使用yml,使用yml的时候需要额外的添加一个jar包依赖,这样springboot才能解析yml中的配置
<!--解析log4j2.yml-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.8.8</version>
</dependency>
一个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使用了哪些默认配置,将日志级别该为debug就可看到,这里给出一部分日志内容:
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双数据源</strong>
=========
这里数据源使用druid,数据库使用mysql,引入mybatis的starter,pom配置如下:
<!--数据库-->
<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>
为了使用双数据源,在配置文件中我们设置两套数据库配置,一套是master,一套是cluster,前缀分别使用masterDb.dataSource和clusterDb.dataSource,同时给出两套不同的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
注解的配置类,第一点需要注意的是这里我们需要引入@MapperScan
注解,给出dao层包的位置,mybatis会自动实现该路径下的所有接口,实现方式是根据类名与同名的mapper文件匹配,将类里面的方法名和mapper文件内的sql语句匹配并以此实现该接口,典型的约定大于配置哈!第二点是可以看出完成mybatis的配置需要数据源的配置,sessionfactory
的配置以及事务管理器的配置。第三点是增加@Primary
注解表明该数据源配置为最高优先,在cluster的配置中不需要改注解。第四点是注意使用不同的bean名称。这样我们已经可以在一个应用中使用两套数据源配置了。
/**
* Created by admin360buyad on 2017-06-07.
* 多数据源配置,配置主数据源
* spring容器可以自动识别哪些Bean需要先装配,下面的代码中,spring首先会注入masterDataSource
* 接下来才是masterSqlSessionFactory和masterDataSourceTm
*/
@Configuration
@MapperScan(basePackages = "com.example.dao.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDbConfig {
/**
* mybatis自动扫描该包下的domain并且根据类名的首字母小写设置别名
*/
@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的最新版本默认已经不支持velocity,所以需要我们通过@Configuration自动配置,首先引入velocity的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
接下来是配置类,我们需要提供VelocityViewResolver和VelocityConfigurer
两个bean。这里对VelocityViewResolver
使用了@Order(1)
表明spring mvc会尝试首先使用该viewResolver
来返回请求(如果存在比1的值更低的order将具有更高优先级),所有的viewResolver
都将被ContentNegotiatingViewResolver
管理,ContentNegotiatingViewResolver
本身不对请求处理,只负责管理其他viewResolver
,并且在其初始化时将获取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静态资源的配置可以写在配置文件
resources:
static-locations: classpath:/statics/
mvc:
static-path-pattern: /resource/**
下载上传的限制也可以
spring:
http:
multipart:
max-file-size: 2MB
spring boot提供了很多默认的mvc配置,如果我们想要修改都可以通过在配置温江中自己配置。
- <strong>springboot测试</strong>
=========
一个简单的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
注解配置测试的启动信息,先看第一个参数classes,其java doc如下,可以看出其作用是通过参数类加载一个spring的上下文,如果改参数未指定将在该测试类内部寻找可加载的配置类
/**
* 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
*/
第二个参数是webEnvironment ,java doc如下,意思是我们创建web环境的类型,默认是一个mock,选项包括
/**
* 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);
该注解还包括如下两个参数用于自定义一些需要使用的属性配置
/**
* 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 {};