從SpringMVC遷移到Springboot

在將SpringMVC項目轉移到Springboot上的過程當中,主要作了如下的事情java

  • Profile配置
  • 全局變量從properties文件讀入
  • 數據源與Mybatis配置
  • 日誌文件配置
  • WebConfig配置(包括原有的web.xml和spring-mvc.xml)
  • 去掉多餘的bean注入

本篇文章除了介紹作了些什麼和怎麼作以外,會多不少多餘的廢話,關於對原理的一些探討,知其然也要知其因此然。web

Profile配置

在傳統的Spring項目中,多個profile的配置方式首先是在pom.xml文件中寫入多個profile,再經過啓動項目前先執行一個maven文件來預加載選定的profile環境。加載完以後,執行項目的時候,會根據已加載的Environment,來決定去將哪一個.properties文件load到全局變量中。spring

而在Springboot中對多個profile的管理就很是簡單了。sql

能夠在jar包用命令行運行時選擇profile數據庫

java -jar example.jar --spring.profiles.active=test
複製代碼

或者在application.properties這個全局配置中配置spring-mvc

在application.properties中添加spring.profiles.active=test
複製代碼

以上兩種方法都可啓動「test"這個profile,前者在執行上的優先級要高於後者。tomcat

(順便一提,在Springboot裏面,這兩種方式本質上都是用「外部化配置」的方式,來對Environment進行編輯和替換)bash

另外,每一個獨立的profiles的配置方式爲以"application-xxx.properties"格式,針對每一個不一樣環境,例如:session

  • application-pro.properties 表示預演環境
  • application-dev.properties 表示開發環境
  • application-test.properties 表示測試環境

當咱們須要測試是否正常載入了profile的時候,能夠在對應的.properties文件中寫入mvc

server.port=9080
複製代碼

在啓動的時候就能夠看到,是否已經啓動了這個端口。

在這裏能夠順便提一下Springboot加載配置文件的順序

  • home目錄下的devtools全局設置屬性( ~/.spring-boot-devtools.properties ,若是devtools激活)。
  • 測試用例上的@TestPropertySource註解。
  • 測試用例上的@SpringBootTest#properties註解。
  • 命令行參數
  • 來自 SPRING_APPLICATION_JSON 的屬性(環境變量或系統屬性中內嵌的內聯JSON)。
  • ServletConfig 初始化參數。
  • ServletContext 初始化參數。
  • 來自於 java:comp/env 的JNDI屬性。
  • Java系統屬性(System.getProperties())。
  • 操做系統環境變量。
  • RandomValuePropertySource,只包含 random.* 中的屬性。
  • 沒有打進jar包的Profile-specific應用屬性( application-{profile}.properties 和YAML變量)。
  • 打進jar包中的Profile-specific應用屬性( application-{profile}.properties 和YAML變量)。
  • 沒有打進jar包的應用配置( application.properties 和YAML變量)。
  • 打進jar包中的應用配置( application.properties 和YAML變量)。
  • @Configuration 類上的 @PropertySource 註解。
  • 默認屬性(使用 SpringApplication.setDefaultProperties 指定)。

全局變量從properties文件讀入

在上一面一小節寫了針對不一樣環境的properties配置,這裏會寫關於若是將這些屬性寫入到全局變量中,方便後面其餘地方直接調用。

/**
 * 全局變量
 */
public class Global {

	public static String examplePath;

	@Value("${example_path}")
    public void setExamplePath(String example) {
        Global.examplePath = examplePath;
    }
}
複製代碼

經過這樣子,咱們便將.properties文件中的

example_path=http://localhost:9090
複製代碼

這個屬性讀到了全局變量中。

數據源與Mybatis配置

在傳統的Spring項目中,用Mybatis鏈接數據庫

  • 首先要建立一個名爲datasource的bean
  • 而後將這個datasource裝配到SqlSessionFactory中
  • 最後再將SqlSessionFactory裝配到MapperScannerConfigurer中

這一切都是在xml配置文件中配置的,比較繁瑣。在Springboot中會盡可能去避免這樣子的xml配置。

Mybatis如今已經爲Springboot提供了支持,咱們只須要添加MyBatis-Spring-Boot-Starter這個依賴,它就會爲咱們去作好如下的事情:

  • 自動檢測已有的datasource
  • 建立一個SqlSessionFactoryBean的實例SqlSessionFactory,並將datasource裝配進去
  • 建立一個SqlSessionTemplate的實例,並將SqlSessionFactory裝配進去
  • 自動掃描你的mapper,將它們鏈接到SqlSessionTemplate,並將它們註冊到Spring的上下文,以便將它們注入到其餘的bean中。

因此,在Springboot的Mybatis配置中,咱們須要去作如下幾件事情:

  1. 在application-{profile}.properties中填入數據庫信息,例如:
spring.datasource.url=jdbc:oracle:thin:@//localhost:1234/example
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.maxActive=10
spring.datasource.maxIdle=5
spring.datasource.maxWait=-1
複製代碼

經過這種方式,咱們便在Spring上下文中註冊了datasource這個bean。

  1. 建立一個MybatisConfig文件,用java的方式取代xml:
/**
 * Created by WuTaoyu on 2017/12/7.
 */
@Configuration
@EnableTransactionManagement
@MapperScan("com.example.db.dao")
public class MybatisConfig {

    @Autowired
    private DataSource dataSource;

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean() {
        SqlSessionFactoryBean sqlsession = new SqlSessionFactoryBean();
        sqlsession.setDataSource(dataSource);
        try {
            //添加XML目錄
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            sqlsession.setMapperLocations(resolver.getResources("classpath:mapping/*.xml"));
            return sqlsession.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }


    @Bean(name = "exampleSequence")
    public OracleSequenceMaxValueIncrementer exampleSequenceBean(){
        OracleSequenceMaxValueIncrementer exampleSequence = new OracleSequenceMaxValueIncrementer();
        exampleSequence.setIncrementerName("EXAMPLE_SEQ");
        exampleSequence.setDataSource(dataSource);
        return exampleSequence;
    }
}
複製代碼

@MapperScan是掃描這個包下面的mapper。

另外這裏mapper.xml的位置,是在resource文件夾下面建了一個mapping文件夾,放在下面。

這裏的做用跟XML比較相似,是將傳統的xml表達方式用.java文件來描述出來,本質上仍是將datasource一步步注入。

因爲示例用的是oracle數據庫,因此最後一個exampleSequence是示範如何添加序列。

  1. 對全部mapper的interface註解@Mapper

例如:

@Mapper
public interface UserMapper {
	...
}
複製代碼

日誌文件配置

Logback支持用properties的方式外部化配置,可是對於比較細的配置來講,仍是要沿用xml配置。

爲了讓xml文件從.properties文件讀取一些路徑之類可能須要常常修改的靜態配置,須要在logback-spring.xml中配置

<property resource="application.properties" />
    <property name="log.root.level" value="${log.root.level}" />
    <property name="log.path" value="${log.path}" />
    <property name="log.moduleName" value="${log.module}" />
複製代碼

這樣子就能夠將application.properties文件中的

log.path=/home/logs/example
log.root.level=INFO
log.module=example
複製代碼

讀入到logback-spring.xml中,而後再去調用。

WebConfig配置

WebConfig的主要做用是替代web.xml和spring-mvc.xml進行一些基礎配置。

  1. 關於web.xml

傳統的Spring項目都有配置一個web.xml文件,這個文件的做用是:當咱們把war包放入應用容器(例如tomcat)中運行時,容器會根據web.xml去加載filter(過濾器)、servlet、error-page、welcome-file-list、listener(監聽器)、context-param(上下文參數)、resource-ref(資源配置)等配置。

包括ContextLoaderListener這個監聽器,就是在這裏加載進去,用於在啓動容器的時候,自動裝配ApplicationContext的配置信息。

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
複製代碼

這個ApplicationContext是Spring IOC的核心(繼承自BeanFactory),全部單例的Bean會在這個時候就被實例化。

以及,SpringMVC中很重要的一個DispatcherServlet也是在這裏加載進去,並制定根據哪一個xml文件來配置DispatcherServlet。

<servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <!--<async-supported>true</async-supported>-->
</servlet>
複製代碼
  1. 關於spring-mvc.xml

spring-mvc.xml是SpringMVC的配置文件,在這裏能夠配置咱們引入的、須要定製化的bean,例如ViewResolver、multipartResolver、HTTP消息轉換器、自定義的攔截器等等。

以上都與Springboot無關,主要是爲了知其然也知其因此然,若是不感興趣的能夠不看。

再講回Springboot的配置。Springboot有一個說法叫「約定優於配置」,就是儘可能用約定的方式,而不是特意去針對性地配置(須要特殊配置的時候再去配置)。

引入spring-boot-starter-web這個「開箱即用」的依賴以後,spring-boot-starter-web下包含了一個spring-boot-autoconfigure

有了這個依賴以後,就可使用@EnableAutoCongiguration註解。這個註解就會根據引入的依賴來猜想你須要的Spring配置並幫你配置好。由於已經引入了spring-boot-starter-web的話,這個註解就會將web相關的配置配置好。

另外,@SpringBootApplication這個註解中已經包含了@EnableAutoCongiguration註解。因此只要在啓動類ExampleServerApplication上註解@SpringBootApplication就能夠自動把web配置給配置好了。

固然,咱們可能還有一些特殊的配置,這時候就能夠建立一個WebConfig去定製

/**
 * Created by WuTaoyu on 2017/12/8.
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(marshallingHttpMessageConverter());
    }

    public MarshallingHttpMessageConverter marshallingHttpMessageConverter(){
        MarshallingHttpMessageConverter marshallingHttpMessageConverter = new MarshallingHttpMessageConverter();
        List<MediaType> mediaTypes = new ArrayList<MediaType>();
        mediaTypes.add(MediaType.TEXT_XML);
        mediaTypes.add(MediaType.APPLICATION_XML);
        XStreamMarshaller xStreamMarshaller=new XStreamMarshaller();
        marshallingHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
        marshallingHttpMessageConverter.setMarshaller(xStreamMarshaller);
        marshallingHttpMessageConverter.setUnmarshaller(xStreamMarshaller);
        return marshallingHttpMessageConverter;
    }
    //配置文件上傳
    @Bean(name = {"multipartResolver"})
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver();
        commonsMultipartResolver.setDefaultEncoding("utf-8");
        commonsMultipartResolver.setMaxUploadSize(10485760000L);
        commonsMultipartResolver.setMaxInMemorySize(40960);
        return commonsMultipartResolver;
    }
    //異常處理
    @Bean
    public ExceptionHandler exceptionResolver(){
        ExceptionHandler exceptionHandler = new ExceptionHandler();
        return exceptionHandler;
    }
    //攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}
複製代碼

我寫的這個示例文件裏面作了幾件事情:

  • 引入一個XML的Http消息轉換器
  • 引入multipartResolver
  • 引入自定義的異常處理器
  • 引入自定義攔截器

去掉多餘的bean注入

這個算是一個題外話,但也是我實際遇到的問題之一。

在實際運行的Springboot項目的時候,我發現了一些在傳統Spring項目中沒有報錯的問題,就是多餘的bean注入。

在傳統Spring項目中,這是沒有報錯的,可是在Springboot項目中就報錯了。我猜想是由於要注入bean的類方法名取的比較精簡的時候,與Springboot自己自動配置的一些bean重複了,就會報錯。

因此,把有些不須要注入的bean去掉吧。

相關文章
相關標籤/搜索