spring boot项目搭建

  1. <strong>写在前面</strong>
    ======
    通过阅读官方文档以及编写一些demo,个人认为spring boot的核心思想是约定大于配置以及使用java配置代替xml配置,简化繁琐的项目配置同时避免维护繁杂的xml文件。
  2. <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,默认使用的端口号,默认的上下文路径,我们就无需再配置。

  1. <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里面另行配置。

  1. <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 {
// ...
}
  1. <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的构造函数注入ApplicationArgumentsApplicationArguments是封装了命令行启动参数的对象

@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);
        }
    }
}
  1. <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)
  1. <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);
    }
}
  1. <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;
    }
}
  1. <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配置,如果我们想要修改都可以通过在配置温江中自己配置。

  1. <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 {};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,227评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,755评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,899评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,257评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,617评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,757评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,982评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,715评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,454评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,666评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,148评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,512评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,156评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,112评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,896评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,809评论 2 279
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,691评论 2 272

推荐阅读更多精彩内容