最近接触spring boot,网上火了好一阵,一开始对这个并不感冒,个人也不是很喜欢将配置写进代码中,所以也就没有去研究它。最近一个项目需要用到spring boot,学习了各路大神的心得后,结合以前的springMVC+spring+mybatis流程,做了一个简单的转换和对比。spring boot这么火热是有道理的,虽然部分配置写进代码,但是非常集中,再也不用在几个配置文件中改来改去,没有一大坨xml配置,jar包运行简直爽。开发热部署极大地提高了开发效率。
maven依赖 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<properties >
<java.version > 1.8</java.version >
</properties >
<parent >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-parent</artifactId >
<version > 1.5.6.RELEASE</version >
</parent >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
<version > 1.5.6.RELEASE</version >
<exclusions >
<exclusion >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-logging</artifactId >
</exclusion >
</exclusions >
</dependency >
<dependency >
<groupId > org.mybatis.spring.boot</groupId >
<artifactId > mybatis-spring-boot-starter</artifactId >
<version > 1.3.1</version >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-log4j2</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-devtools</artifactId >
<optional > true</optional >
</dependency >
<dependency >
<groupId > org.aspectj</groupId >
<artifactId > aspectjweaver</artifactId >
</dependency >
<dependency >
<groupId > com.alibaba</groupId >
<artifactId > druid</artifactId >
<version > 1.1.3</version >
</dependency >
<dependency >
<groupId > com.oracle</groupId >
<artifactId > ojdbc</artifactId >
<version > 12c</version >
</dependency >
.....
<build >
<plugins >
<plugin >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-maven-plugin</artifactId >
<version > 1.5.6.RELEASE</version >
<dependencies >
<dependency >
<groupId > org.springframework</groupId >
<artifactId > springloaded</artifactId >
<version > 1.2.6.RELEASE</version >
</dependency >
</dependencies >
<configuration >
<fork > true</fork >
</configuration >
</plugin >
</plugins >
</build >
上面是spring boot需要的依赖,比传统方式少了很多。
application.yml文件 spring boot的配置文件可以是properties文件,也可以是yml文件,推荐使用yml文件,结构比较清晰。spring boot通过profile可以指定开发模式、发布模式和测试模式下的配置文件,具体结构如下:1
2
3
4
5
|--resources:
|---application.yml
|---application-dev.yml
|---application-test.yml
|---application-release.yml
application-dev.yml、application-test.yml和application-release.yml分别对应开发模式、测试模式和发布模式的配置文件,这三个文件里面放一些不同环境下配置不同的参数,比如数据库连接等信息。application.yml则放一些三个环境都相同的配置。其中application.yml第一句需要一个配置指定当前的环境1
2
3
spring:
profiles:
active: dev
如上,指定为开发模式,则application-dev.yml配置文件生效。
spring boot可以通过配置文件来注入属性或者修改默认的配置,也可以通过命令行载入,它支持多种外部配置方式,这些优先级顺序如下(由高到低):
命令行参数
来自java:comp/env的JNDI属性
Java系统属性(System.getProperties())
操作系统环境变量
RandomValuePropertySource配置的random.*属性值
jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
jar包外部的application.properties或application.yml(不带spring.profile)配置文件
jar包内部的application.properties或application.yml(不带spring.profile)配置文件
@Configuration注解类上的@PropertySource
通过SpringApplication.setDefaultProperties指定的默认属性
spring boot内嵌Tomcat,关于Tomcat的配置也可以在配置文件指定,一个包含简单运行环境的配置如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: ${port:8081 }
context-path: /springboot-demo
tomcat:
uri-encoding: UTF-8
spring:
http:
encoding:
charset: UTF-8
enabled: true
force: true
multipart:
enabled: true
max-file-size: 100 MB
max-request-size: 100 MB
messages:
encoding: UTF-8
基础配置一些编码格式。context-path:/springboot-demo
是配置上下文,默认是/
,访问时需要加上下文localhost:8081//springboot-demo/xxx
。port: ${port:8081}
表示Tomcat默认在端口8081运行,可以通过命令行的方式重置java -jar xxx.jar --port 8084
。这是一种简化的命令行配置方式。假如yml的配置是
需要在命令行重置端口,需要执行java -jar xxx.jar --server.port 8084
,如果要修改一个比较长的参数,输入就比较麻烦了。
运行spring boot 1
2
3
4
5
6
7
8
9
10
11
12
@EnableAutoConfiguration
@Configuration
@ComponentScan
@ServletComponentScan
@EnableTransactionManagement
public class Application {
public static void main (String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setWebEnvironment(true );
app.run(args);
}
}
包含main方法的类必须放在根包下。
Tomcat 相关 filter 在传统方式中,filter是在web.xml文件配置的,在spring boot中简化为注解配置。1
2
3
public class ParamFilter implements Filter {
xxx
}
传统方式配置 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<filter >
<filter-name > paramFilter</filter-name >
<filter-class > com.xxx.ParamFilter</filter-class >
<init-param >
<param-name > exclusions</param-name >
<param-value > /res/*,*.html,*.jsp,*.css,*.js,*.png,*.jpg</param-value >
</init-param >
</filter >
<filter-mapping >
<filter-name > paramFilter</filter-name >
<url-pattern > *.action</url-pattern >
</filter-mapping >
<filter-mapping >
<filter-name > paramFilter</filter-name >
<url-pattern > *.jsp</url-pattern >
</filter-mapping >
spring boot 1
2
3
4
5
6
7
8
9
10
11
@WebFilter (
urlPatterns = {"*.action" ,"*.jsp" },
filterName = "paramFilter" ,
initParams = {
@WebInitParam (name="exclusions" ,value = "/res/*,*.html,*.jsp,*.css,*.js,*.png,*.jpg" )
}
)
@Order (1 )
public class ParamFilter implements Filter {
xxx
}
@Order(1)
注解是设定filter的执行顺序,越小越先执行,web.xml方式是按照定义的顺序执行。
listener 1
2
3
public class ApplicationServletContextListener implements ServletContextListener {
xxx
}
传统方式配置 1
2
3
<listener >
<listener-class > com.xxx.ApplicationServletContextListener</listener-class >
</listener >
spring boot方式 1
2
3
4
@WebListener
public class IndexListener implements ServletContextListener {
xxx
}
servlet 1
2
3
public class IndexServlet extends HttpServlet {
xxx
}
传统方式 1
2
3
4
5
6
7
8
9
10
11
12
13
<servlet >
<servlet-name > indexServlet</servlet-name >
<servlet-class > org.xxx.indexServlet</servlet-class >
<init-param >
<param-name > location</param-name >
<param-value > xxxx</param-value >
</init-param >
<load-on-startup > 1</load-on-startup >
</servlet >
<servlet-mapping >
<servlet-name > indexServlet</servlet-name >
<url-pattern > *.action</url-pattern >
</servlet-mapping >
spring boot方式 1
2
3
4
5
6
7
8
9
10
11
@WebServlet (
name = "indexServlet" ,
urlPatterns = "*.action" ,
loadOnStartup = 1 ,
initParams = {
@WebInitParam (name="location" ,value ="xxxx" )
}
)
public class IndexServlet extends HttpServlet {
xxx
}
上面配置完了后,需要在main所在类加一个注解@ServletComponentScan
。 在spring boot中还有一种通过java bean的方式配置,不如注解简单直观,可自行搜索。此处贴出网上的一段代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Bean
public ServletRegistrationBean indexServletRegistration () {
ServletRegistrationBean registration = new ServletRegistrationBean(new IndexServlet());
registration.addUrlMappings("/hello" );
return registration;
}
@Bean
public FilterRegistrationBean indexFilterRegistration () {
FilterRegistrationBean registration = new FilterRegistrationBean(new IndexFilter());
registration.addUrlPatterns("/" );
return registration;
}
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean () {
ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
servletListenerRegistrationBean.setListener(new IndexListener());
return servletListenerRegistrationBean;
}
spring boot在使用spring MVC时是不需要配置DispatcherServlet,因为已经自动配置了,如果需要加一些初始配置参数,可以使用bean的方式解决1
2
3
4
5
6
7
@Bean
public ServletRegistrationBean dispatcherRegistration (DispatcherServlet dispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
registration.addUrlMappings("*.action" );
registration.addUrlMappings("*.jsp" );
return registration;
}
上面方法中的DispatcherServlet参数是spring自动注入进来的。
404 500配置 传统方式 1
2
3
4
5
6
7
8
<error-page >
<error-code > 500</error-code >
<location > /500.html</location >
</error-page >
<error-page >
<error-code > 404</error-code >
<location > /404.html</location >
</error-page >
spring boot 1
2
3
4
5
6
7
8
9
10
11
12
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer () {
return new EmbeddedServletContainerCustomizer(){
@Override
public void customize (ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html" );
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html" );
configurableEmbeddedServletContainer.addErrorPages( error404Page, error500Page);
configurableEmbeddedServletContainer.setRegisterDefaultServlet(true );
}
};
}
Mybatis 在application-{profile}.yml添加配置1
2
3
mybatis:
mapperLocations: classpath*:com/xxx/**/model/*.xml
configLocation: classpath:mybatis-config.xml
关于mybatis的配置文件还是依照mybatis-config.xml的形式,跟以前一样。
druid数据库连接池 在application-{profile}.yml添加配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@10.43 .164 .148 :1521 :orcl
username: c
password: 1234567890
initialSize: 1
minIdle: 5
maxActive: 50
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 1 from dual
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: false
maxPoolPreparedStatementPerConnectionSize: 20
removeAbandoned: true
removeAbandonedTimeout: 1800
logAbandoned: true
filters: stat,log4j
connectionProperties: druid.stat.slowSqlMillis=5000
由于spring boot内置的数据库连接池不支持druid,所以需要自己创建bean1
2
3
4
5
6
7
@Bean (initMethod = "init" ,destroyMethod = "close" )
@ConfigurationProperties (prefix = "spring.datasource" )
@Primary
public DataSource druidDataSource () {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
上面@ConfigurationProperties(prefix = "spring.datasource")
注解是spring boot读取配置的一种方式,将所有以spring.datasource
开头的配置读入,再注入到DataSource Bean中。@Primary
表示这里定义的DataSource将覆盖其他来源的DataSource。
SqlSession与事务 SqlSessionFactory
spring boot监测到DataSource存在时,会创建并注册SqlSessionFactoryBean实例,并传入Datasource,在mybatis中,sqlsession可以由SqlSessionFactory创建;而在mybatis-spring中则需要SqlSessionFactoryBean来创建,并传入datasource。1
2
3
4
5
6
7
8
9
<bean id ="defaultSQLSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" >
<property name ="dataSource" ref ="defaulteDataSource" />
<property name ="configLocation" value ="classpath:mybatis-config.xml" > </property >
<property name ="mapperLocations" >
<array >
<value > classpath*:com/xxx/**/model/*.xml</value >
</array >
</property >
</bean >
现在,mybatis-spring-boot支持自动创建并注册SqlSessionFactoryBean,所以以上的配置都不需要了
SqlSessionTemplate SqlSessionTemplate是SqlSession的实现类,较SqlSession的默认实现类DefaultSqlSession来说,是线程安全的。在以前的方式中中需要如下配置1
2
3
<bean id ="defaultSQLSessionTemplate" class ="org.mybatis.spring.SqlSessionTemplate" scope ="prototype" >
<constructor-arg index ="0" ref ="defaultSQLSessionFactory" />
</bean >
mybatis-spring-boot支持自动创建并注册SqlSessionTemplate,所以不需要以上配置了
使用SqlSession时直接注入就行1
2
@Autowired
private SqlSession sqlSession;
事务配置
传统方式使用事务配置如下1
2
3
4
5
6
<bean id ="defaultTransactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name ="dataSource" ref ="defaulteDataSource" />
</bean >
<tx:annotation-driven transaction-manager ="defaultTransactionManager" />
在spring boot中,开启事务简单了许多,在main方法所在类加入@EnableTransactionManagement
就开启了事务支持,在service类或方法上添加@Transactional
注解,执行的方法就支持事务了。
关于事务管理器,不管是JPA还是JDBC等都实现自接口PlatformTransactionManager,如果添加的是 spring-boot-starter-jdbc依赖,框架会默认注入DataSourceTransactionManager实例。如果你添加的是 spring-boot-starter-data-jpa依赖,框架会默认注入JpaTransactionManager 实例。
mybatis-spring-boot-starter
默认依赖了spring-boot-starter-jdbc
。
实现多个事务管理器可以参考这篇博客 Spring Boot 事务的使用 。
spring及MVC 1
2
<context:component-scan base-package ="com.xxx.**.controller" />
传统方式中上面这个配置不需要了,在main方法所在类添加@ComponentScan
注解,不用指定basePackage。
spring boot中关于MVC部分的配置基本都是通过继承WebMvcConfigurerAdapter
类重写其中的方法完成。1
2
3
4
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
}
需要在类上添加注解@Configuration
,下面没有特殊说明都是重写该类的方法。
创建bean 传统xml配置方法 1
2
3
4
5
6
7
8
<bean id ="appConfigConstant" class ="com.xxx.AppConfigConstant" init-method ="init" >
<property name ="sqlSessionFactory" ref ="defaultSQLSessionFactory" > </property >
<property name ="configTypes" >
<list >
<value > BSSUTILS</value >
</list >
</property >
</bean >
spring boot 1
2
3
4
5
6
7
@Bean (initMethod="init" )
public AppConfigConstant createAppConfigConstant (@Autowired SqlSessionFactory sqlSessionFactory) throws Exception {
AppConfigConstant appConfigConstant = new AppConfigConstant();
appConfigConstant.setSqlSessionFactory(sqlSessionFactory);
appConfigConstant.setConfigTypes(Arrays.asList("BSSUTILS" ));
return appConfigConstant;
}
拦截器 传统方式 1
2
3
4
5
6
<mvc:interceptors >
<mvc:interceptor >
<mvc:mapping path ="/**/*.action" />
<bean class ="com.xxx.XxxxInterceptor" />
</mvc:interceptor >
</mvc:interceptors >
spring boot 实现了一个日志拦截器AccessLogHandlerInterceptor
,注册方式如下:1
2
3
4
5
6
@Override
public void addInterceptors (InterceptorRegistry registry) {
registry.addInterceptor(new AccessLogHandlerInterceptor())
.addPathPatterns("/**/*.action" );
}
消息转换器 继承自MappingJackson2HttpMessageConverter
类实现自定义JSON消息转换器JSONMessageConverter
传统方式 1
2
3
4
5
<mvc:annotation-driven >
<mvc:message-converters >
<bean class ="com.xxx.JSONMessageConverter" />
</mvc:message-converters >
</mvc:annotation-driven >
spring boot 1
2
3
4
5
@Override
public void configureMessageConverters (List<HttpMessageConverter<?>> converters) {
converters.add(new JSONMessageConverter());
}
启用默认servlet 传统方式 1
<mvc:default-servlet-handler />
关于<mvc:default-servlet-handler />
可以参考博客【Spring框架】的作用
spring boot 1
2
3
4
5
@Override
public void configureDefaultServletHandling (DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
资源目录映射 传统方式 1
2
<mvc:resources location ="/resources/" mapping ="/resources/**" cache-period ="1024" />
spring boot 1
2
3
4
5
6
7
8
@Override
public void addResourceHandlers (ResourceHandlerRegistry registry) {
String rePath = "file:/" +Application.appRuntimePath+"/upload/" ;
registry.addResourceHandler("/upload/**" ).addResourceLocations(rePath).setCachePeriod(1024 );
}
上面例子中Application.appRuntimePath
是jar运行时jar包所在目录(全路径),这属性值是在main方法中动态获取的,目的是在jar包所在目录创建一个文件上传目录,然后在动态映射,以实现文件上传的目的(映射全路径时需要加file:/
前缀)。获取方法如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
* 发布时获取jar包所在目录
* 开发时获取src目录的上层目录
* @return
*/
private static String getRuntimePath () {
try {
String path = Application.class.getProtectionDomain().getCodeSource().getLocation().getPath();
path = URLDecoder.decode(path,"UTF-8" );
String fileSeparator = File.separator;
if (path.contains("/" )){
fileSeparator = "/" ;
}
Pattern pattern = Pattern.compile(fileSeparator+"[-a-zA-Z0-9_]+\\.jar" );
Matcher matcher = pattern.matcher(path);
if (matcher.find()){
int end = matcher.start();
path = path.substring(6 ,end);
}else {
path = path.replace(fileSeparator+"target" +fileSeparator+"classes" +fileSeparator,"" );
int end = path.lastIndexOf(fileSeparator);
path = path.substring(1 ,end);
}
return path;
}catch (Exception e){
e.printStackTrace();
}
return null ;
}
仅在windows环境下测试通过,Linux暂未测试。参考自博客 获得执行jar的运行路径 。
视图解析器 传统方式 1
2
3
4
5
6
7
<bean id ="jspViewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name ="viewClass" value ="org.springframework.web.servlet.view.JstlView" />
<property name ="prefix" value ="/" />
<property name ="suffix" value =".html" />
<property name ="order" value ="1" />
</bean >
spring boot 1
2
3
4
5
6
7
8
9
@Override
public void configureViewResolvers (ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/" );
resolver.setSuffix(".html" );
resolver.setOrder(1 );
registry.viewResolver(resolver);
}
property-placeholder 传统方式 1
<context:property-placeholder location ="appconfig.properties" />
spring boot 1
2
3
4
5
6
7
@Bean
public PropertySourcesPlaceholderConfigurer createPropertySourcesPlaceholderConfigurer () {
ClassPathResource resource = new ClassPathResource("appconfig.properties" );
PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertyPlaceholderConfigurer.setLocations(resource);
return propertyPlaceholderConfigurer;
}