從SpringMVC遷移到Springboot的方法步驟
在將SpringMVC項(xiàng)目轉(zhuǎn)移到Springboot上的過(guò)程中,主要做了以下的事情
- Profile配置
- 全局變量從properties文件讀入
- 數(shù)據(jù)源與Mybatis配置
- 日志文件配置
- WebConfig配置(包括原有的web.xml和spring-mvc.xml)
- 去掉多余的bean注入
本篇文章除了介紹做了些什么和怎么做之外,會(huì)多很多多余的廢話(huà),關(guān)于對(duì)原理的一些探討,知其然也要知其所以然。
Profile配置
在傳統(tǒng)的Spring項(xiàng)目中,多個(gè)profile的配置方式首先是在pom.xml文件中寫(xiě)入多個(gè)profile,再通過(guò)啟動(dòng)項(xiàng)目前先執(zhí)行一個(gè)maven文件來(lái)預(yù)加載選定的profile環(huán)境。加載完之后,執(zhí)行項(xiàng)目的時(shí)候,會(huì)根據(jù)已加載的Environment,來(lái)決定去將哪個(gè).properties文件load到全局變量中。
而在Springboot中對(duì)多個(gè)profile的管理就非常簡(jiǎn)單了。
可以在jar包用命令行運(yùn)行時(shí)選擇profile
java -jar example.jar --spring.profiles.active=test
或者在application.properties這個(gè)全局配置中配置
在application.properties中添加spring.profiles.active=test
以上兩種方法均可啟動(dòng)“test"這個(gè)profile,前者在執(zhí)行上的優(yōu)先級(jí)要高于后者。
(順便一提,在Springboot里面,這兩種方式本質(zhì)上都是用“外部化配置”的方式,來(lái)對(duì)Environment進(jìn)行編輯和替換)
另外,每個(gè)獨(dú)立的profiles的配置方式為以"application-xxx.properties"格式,針對(duì)每個(gè)不同環(huán)境,例如:
- application-pro.properties 表示預(yù)演環(huán)境
- application-dev.properties 表示開(kāi)發(fā)環(huán)境
- application-test.properties 表示測(cè)試環(huán)境
當(dāng)我們需要測(cè)試是否正常載入了profile的時(shí)候,可以在對(duì)應(yīng)的.properties文件中寫(xiě)入
server.port=9080
在啟動(dòng)的時(shí)候就可以看到,是否已經(jīng)啟動(dòng)了這個(gè)端口。
在這里可以順便提一下Springboot加載配置文件的順序
- home目錄下的devtools全局設(shè)置屬性( ~/.spring-boot-devtools.properties ,如果devtools激活)。
- 測(cè)試用例上的@TestPropertySource注解。
- 測(cè)試用例上的@SpringBootTest#properties注解。
- 命令行參數(shù)
- 來(lái)自 SPRING_APPLICATION_JSON 的屬性(環(huán)境變量或系統(tǒng)屬性中內(nèi)嵌的內(nèi)聯(lián)JSON)。
- ServletConfig 初始化參數(shù)。
- ServletContext 初始化參數(shù)。
- 來(lái)自于 java:comp/env 的JNDI屬性。
- Java系統(tǒng)屬性(System.getProperties())。
- 操作系統(tǒng)環(huán)境變量。
- RandomValuePropertySource,只包含 random.* 中的屬性。
- 沒(méi)有打進(jìn)jar包的Profile-specific應(yīng)用屬性( application-{profile}.properties 和YAML變量)。
- 打進(jìn)jar包中的Profile-specific應(yīng)用屬性( application-{profile}.properties 和YAML變量)。
- 沒(méi)有打進(jìn)jar包的應(yīng)用配置( application.properties 和YAML變量)。
- 打進(jìn)jar包中的應(yīng)用配置( application.properties 和YAML變量)。
- @Configuration 類(lèi)上的 @PropertySource 注解。
- 默認(rèn)屬性(使用 SpringApplication.setDefaultProperties 指定)。
全局變量從properties文件讀入
在上一面一小節(jié)寫(xiě)了針對(duì)不同環(huán)境的properties配置,這里會(huì)寫(xiě)關(guān)于如果將這些屬性寫(xiě)入到全局變量中,方便后面其他地方直接調(diào)用。
/** * 全局變量 */ public class Global { public static String examplePath; @Value("${example_path}") public void setExamplePath(String example) { Global.examplePath = examplePath; } }
通過(guò)這樣子,我們便將.properties文件中的
example_path=http://localhost:9090
這個(gè)屬性讀到了全局變量中。
數(shù)據(jù)源與Mybatis配置
在傳統(tǒng)的Spring項(xiàng)目中,用Mybatis連接數(shù)據(jù)庫(kù)
- 首先要?jiǎng)?chuàng)建一個(gè)名為datasource的bean
- 然后將這個(gè)datasource裝配到SqlSessionFactory中
- 最后再將SqlSessionFactory裝配到MapperScannerConfigurer中
這一切都是在xml配置文件中配置的,比較繁瑣。在Springboot中會(huì)盡量去避免這樣子的xml配置。
Mybatis現(xiàn)在已經(jīng)為Springboot提供了支持,我們只需要添加MyBatis-Spring-Boot-Starter這個(gè)依賴(lài),它就會(huì)為我們?nèi)プ龊靡韵碌氖虑椋?/p>
- 自動(dòng)檢測(cè)已有的datasource
- 創(chuàng)建一個(gè)SqlSessionFactoryBean的實(shí)例SqlSessionFactory,并將datasource裝配進(jìn)去
- 創(chuàng)建一個(gè)SqlSessionTemplate的實(shí)例,并將SqlSessionFactory裝配進(jìn)去
- 自動(dòng)掃描你的mapper,將它們連接到SqlSessionTemplate,并將它們注冊(cè)到Spring的上下文,以便將它們注入到其他的bean中。
所以,在Springboot的Mybatis配置中,我們需要去做以下幾件事情:
在application-{profile}.properties中填入數(shù)據(jù)庫(kù)信息,例如:
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
通過(guò)這種方式,我們便在Spring上下文中注冊(cè)了datasource這個(gè)bean。
創(chuàng)建一個(gè)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 { //添加X(jué)ML目錄 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是掃描這個(gè)包下面的mapper。
另外這里mapper.xml的位置,是在resource文件夾下面建了一個(gè)mapping文件夾,放在下面。
這里的作用跟XML比較類(lèi)似,是將傳統(tǒng)的xml表達(dá)方式用.java文件來(lái)描述出來(lái),本質(zhì)上還是將datasource一步步注入。
由于示例用的是oracle數(shù)據(jù)庫(kù),所以最后一個(gè)exampleSequence是示范如何添加序列。
對(duì)所有mapper的interface注解@Mapper
例如:
@Mapper public interface UserMapper { ... }
日志文件配置
Logback支持用properties的方式外部化配置,但是對(duì)于比較細(xì)的配置來(lái)說(shuō),還是要沿用xml配置。
為了讓xml文件從.properties文件讀取一些路徑之類(lèi)可能需要經(jīng)常修改的靜態(tài)配置,需要在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中,然后再去調(diào)用。
WebConfig配置
WebConfig的主要作用是替代web.xml和spring-mvc.xml進(jìn)行一些基礎(chǔ)配置。
1、關(guān)于web.xml
傳統(tǒng)的Spring項(xiàng)目都有配置一個(gè)web.xml文件,這個(gè)文件的作用是:當(dāng)我們把war包放入應(yīng)用容器(例如tomcat)中運(yùn)行時(shí),容器會(huì)根據(jù)web.xml去加載filter(過(guò)濾器)、servlet、error-page、welcome-file-list、listener(監(jiān)聽(tīng)器)、context-param(上下文參數(shù))、resource-ref(資源配置)等配置。
包括ContextLoaderListener這個(gè)監(jiān)聽(tīng)器,就是在這里加載進(jìn)去,用于在啟動(dòng)容器的時(shí)候,自動(dòng)裝配ApplicationContext的配置信息。
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
這個(gè)ApplicationContext是Spring IOC的核心(繼承自BeanFactory),所有單例的Bean會(huì)在這個(gè)時(shí)候就被實(shí)例化。
以及,SpringMVC中很重要的一個(gè)DispatcherServlet也是在這里加載進(jìn)去,并制定根據(jù)哪個(gè)xml文件來(lái)配置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>
2、關(guān)于spring-mvc.xml
spring-mvc.xml是SpringMVC的配置文件,在這里可以配置我們引入的、需要定制化的bean,例如ViewResolver、multipartResolver、HTTP消息轉(zhuǎn)換器、自定義的攔截器等等。
以上都與Springboot無(wú)關(guān),主要是為了知其然也知其所以然,如果不感興趣的可以不看。
再講回Springboot的配置。Springboot有一個(gè)說(shuō)法叫“約定優(yōu)于配置”,就是盡量用約定的方式,而不是特地去針對(duì)性地配置(需要特殊配置的時(shí)候再去配置)。
引入spring-boot-starter-web這個(gè)“開(kāi)箱即用”的依賴(lài)之后,spring-boot-starter-web下包含了一個(gè)spring-boot-autoconfigure。
有了這個(gè)依賴(lài)之后,就可以使用@EnableAutoCongiguration注解。這個(gè)注解就會(huì)根據(jù)引入的依賴(lài)來(lái)猜測(cè)你需要的Spring配置并幫你配置好。因?yàn)橐呀?jīng)引入了spring-boot-starter-web的話(huà),這個(gè)注解就會(huì)將web相關(guān)的配置配置好。
另外,@SpringBootApplication這個(gè)注解中已經(jīng)包含了@EnableAutoCongiguration注解。所以只要在啟動(dòng)類(lèi)ExampleServerApplication上注解@SpringBootApplication就可以自動(dòng)把web配置給配置好了。
當(dāng)然,我們可能還有一些特殊的配置,這時(shí)候就可以創(chuàng)建一個(gè)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); } }
我寫(xiě)的這個(gè)示例文件里面做了幾件事情:
- 引入一個(gè)XML的Http消息轉(zhuǎn)換器
- 引入multipartResolver
- 引入自定義的異常處理器
- 引入自定義攔截器
去掉多余的bean注入
這個(gè)算是一個(gè)題外話(huà),但也是我實(shí)際遇到的問(wèn)題之一。
在實(shí)際運(yùn)行的Springboot項(xiàng)目的時(shí)候,我發(fā)現(xiàn)了一些在傳統(tǒng)Spring項(xiàng)目中沒(méi)有報(bào)錯(cuò)的問(wèn)題,就是多余的bean注入。
在傳統(tǒng)Spring項(xiàng)目中,這是沒(méi)有報(bào)錯(cuò)的,但是在Springboot項(xiàng)目中就報(bào)錯(cuò)了。我猜測(cè)是因?yàn)橐⑷隻ean的類(lèi)方法名取的比較精簡(jiǎn)的時(shí)候,與Springboot本身自動(dòng)配置的一些bean重復(fù)了,就會(huì)報(bào)錯(cuò)。
所以,把有些不需要注入的bean去掉吧。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springboot+vue實(shí)現(xiàn)七牛云頭像的上傳
本文將介紹如何在Spring Boot項(xiàng)目中利用七牛云進(jìn)行圖片上傳并將圖片存儲(chǔ)在云存儲(chǔ)中,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08java鏈表應(yīng)用--基于鏈表實(shí)現(xiàn)隊(duì)列詳解(尾指針操作)
這篇文章主要介紹了java鏈表應(yīng)用--基于鏈表實(shí)現(xiàn)隊(duì)列,結(jié)合實(shí)例形式分析了java基于鏈表實(shí)現(xiàn)隊(duì)列尾指針相關(guān)操作使用技巧,需要的朋友可以參考下2020-03-03Spring?Kafka中如何通過(guò)參數(shù)配置解決超時(shí)問(wèn)題詳解
這篇文章主要給大家介紹了關(guān)于Spring?Kafka中如何通過(guò)參數(shù)配置解決超時(shí)問(wèn)題的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01java(swing)+ mysql實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)源碼
這篇文章主要分享了java mysql實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)的源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11詳解MyBatis的getMapper()接口、resultMap標(biāo)簽、Alias別名、 盡量提取sql列、動(dòng)態(tài)操作
這篇文章主要介紹了詳解MyBatis的getMapper()接口、resultMap標(biāo)簽、Alias別名、 盡量提取sql列、動(dòng)態(tài)操作的相關(guān)資料,需要的朋友可以參考下2016-08-08JAVA應(yīng)用系統(tǒng)工具快捷托盤(pán)實(shí)例代碼
JAVA應(yīng)用系統(tǒng)工具快捷托盤(pán)實(shí)例代碼,需要的朋友可以參考一下2013-02-02剖析Java中在Collection集合中使用contains和remove為什么要重寫(xiě)equals
這篇文章主要介紹了Collection集合的contains和remove方法詳解remove以及相關(guān)的經(jīng)驗(yàn)技巧,通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09SpringCloud如何引用xxjob定時(shí)任務(wù)
Spring?Cloud?本身不直接支持?XXL-JOB?這樣的定時(shí)任務(wù)框架,如果你想在?Spring?Cloud?應(yīng)用中集成?XXL-JOB,你需要手動(dòng)進(jìn)行配置,本文給大家介紹SpringCloud如何引用xxjob定時(shí)任務(wù),感興趣的朋友一起看看吧2024-04-04