Spring具有繁琐的xml配置,目前Spring从3.x过渡到4.x的版本,推荐使用Java配置取代xml配置。Spring boot并不是什么新的技术或功能,只是为Spring框架整合许多第三方的技术。
1.Spring的Java配置方式
1.1基本注解@Configuration和@Bean
java配置方式主要通过**@Configuration和@Bean**这两个注解来实现的。
- @Configuration 作用于类上,相当于一个xml配置文件
- @Bean作用于方法上,相当于xml中的<bean>标签
下面Java配置具体代码的实现,和之前xml配置不同就是多了这个文件,省去了xml的配置,其他的实体类、服务层、Controller都一样的写法
package cn.itcast.springboot.javaconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
*
* @author Weiguo Liu
* @data 2017年11月27日
*/
//这个注解,表明该类是一个Spring的配置,相当于一个xml文件
@Configuration
//配置扫描包,即Spring管理的文件包路径
@ComponentScan(basePackages = "cn.itcast.springboot.javaconfig")
public class SpringConfig {
@Bean// 通过该注解来表明是一个Bean对象,相当于xml中的<bean>标签,这里提供一个获取Dao的方法即可
public UserDAO getUserDAO() {
return new UserDAO(); // 直接new对象做演示
}
}
1.2 读取外部资源配置文件
以前通过xml配置是通过context:property-placeholder这个标签来配置文件地址,辅助${xx}这样方式获取具体的配置属性,在Java注解配置,用一个SpringConfiguration.java文件代替了xml,所以外部文件的引入也是在这个配置文件上做文章,外部资源文件的引入直接在Configuration类上加上@PropertySource(value={"classpath:xxx"})
即可引入(xxx表示配置文件名,通常是"xxx.properties"的形式),然后在配置文件中配置具体属性的时候,直接在该属性上用@Value注解注入即可,和xml中的表示一样:比如@Value("${jdbc.url}")
当然如果需要引入多个外部文件就应该写成@PropertySource(value={"classpath:xxx","classpath:外部文件2"})
这里因为可能引入的外部文件不存在,所以通常会配置一个忽略不存在的外部文件的设置
@PropertySource(value = { "classpath:jdbc.properties" }, ignoreResourceNotFound = true)
下面是具体的典型综合配置代码
配置文件jdbc.properties还像之前那么写即可
package cn.itcast.springboot.javaconfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.jolbox.bonecp.BoneCPDataSource;
/**
*
* @author Weiguo Liu
* @data 2017年11月27日
*/
//这个注解,表明该类是一个Spring的配置,相当于一个xml文件
@Configuration
//配置扫描包,即Spring管理的文件包路径
@ComponentScan(basePackages = "cn.itcast.springboot.javaconfig")
//引入外部配置文件,忽略不存在的文件
@PropertySource(value = { "classpath:jdbc.properties" }, ignoreResourceNotFound = true)
public class SpringConfig {
@Bean// 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
public UserDAO getUserDAO() {
return new UserDAO(); // 直接new对象做演示
}
//获取配置文件中的一些具体的属性
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.driverClass}")
private String driverClass;
//destroyMethod="close"的作用当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用.
@Bean(destroyMethod="close")
//这里使用的连接池不同,所以获取的对象会有所不同,通常会写成getBoneCPDataSource
//但是Spring中会默认使用方法名作为bean的id,使用getxx不太适合,故改成boneCPDataSource
public BoneCPDataSource boneCPDataSource() {
BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
boneCPDataSource.setUsername(userName);
boneCPDataSource.setPassword(password);
boneCPDataSource.setJdbcUrl(jdbcUrl);
boneCPDataSource.setDriverClass(driverClass);
// 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0
boneCPDataSource.setIdleConnectionTestPeriodInMinutes(60);
// 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0
boneCPDataSource.setIdleMaxAgeInMinutes(30);
// 每个分区最大的连接数
boneCPDataSource.setMaxConnectionsPerPartition(100);
// 每个分区最小的连接数
boneCPDataSource.setMinConnectionsPerPartition(5);
return boneCPDataSource;
}
}
2.Spring Boot
以上基于Java注解的叨叨就是为了Spring Boot的引入,它里面基本都是注解。
静态语言:先编译,再运行
动态语言:不需要编译,直接运行
Java是属于静态语言
JS属于动态语言
spring boot可以快速运行项目,之所以运行快速是因为实际上实在运行的一个jar,而不是一个工程,所以spring boot适用于开发测试(独立运行的jar,内嵌SERVLET容器(实际就是Tomcat)不需要再将它部署到Tomcat中),不太适合实际运用,但是还是可以将整个项目作为一个war包发布到生产环境中去。总而言之,在开发测试阶段运行的就是一个独立的jar包,但是在开发完之后打包成war包,丢到生产环境中,他又是一个完整的项目,非常方便,使用Spring boot可以极少使用或者不用Spring的配置(很多都已经内置了)。
2.1 Spring boot的必须引入的依赖
- spring项目必须将parent设为spring boot
它包含了大量的默认配置,大大简化了我们的开发
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/>
</parent>
注意在其后引入的一些spring的一些模块时,不需要再写版本号version,因为这个里面已经包含了整个spring的版本号
- 如果是开发web项目,必须引入web支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 添加spring boot的插件(可省)
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
2.2 简单的Spring boot应用
1.xxxApplication
一般情况下,Springboot项目都会有一个叫做xxxApplication的类,这个类就是整个项目的入口,如下:
package cn.itcast.springboot.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@SpringBootApplication//表明是一个Springboot的应用
@Controller//表明是SpringMVC的类Contrller
@Configuration//表明自身就是一个配置文件
public class HelloApplication {
@RequestMapping("hello")
@ResponseBody//有这个注解就会使用消息转化器输出返回的字符串
public String hello() {
return "hello world!";
}
public static void main(String[] args) {
//SpringApplication.run()方法中传入的类必须要有@SpringBootApplication注解,然后运行这个类
//这个类其实就是Spring Boot的入口方法
SpringApplication.run(HelloApplication.class, args);
}
}
【注意】
- @SpringBootApplication是Spring Boot项目的核心注解,主要作用是开启自启动配置,是组合注解,里面也配置了自动扫描该App同级目录以及子目录下的所有类,如果不想让它自动配置哪个,后面可以接(execlude={xxx.class}),即可对xxx这个类不进行自动配置
- @Configuration是设置Spring的配置类,通常spring boot项目中推荐使用@SpringBootConfiguration代替它(它的底层包含了@Configuration这个注解)
- @Controller表示该类是一个SpringMVC的Controller控制器
- main方法是启动一个应用,就是Spring boot应用的入口
2. spring boot项目的启动
spring boot项目中有两种启动方式,一种是直接运行xxxApplication(run As Java Application)获取右击项目RunAs–>Spring boot App;另一种是采用Maven插件的方式运行,刚刚2.1中第3部配置spring boot maven的插件就提供了这个作用,步骤如下:
右击项目–>Run As–>Run Configurations–>Maven Build–>右击new,出现如下窗口
Name随意填写,Base directory选择项目所在位置即可,Goals填入maven的启动命令:spring-boot:run即可,最后点击run便可运行。
3.启动日志
启动这个类的时候控制台会输出如下的一些信息
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) ) //这个是spring boot的logo,其实上是个banner,默认是这个,当然可以随意改
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.2.RELEASE) //Spring Boot的版本号
2017-11-27 12:51:54.247 INFO 13288 --- [ main] c.i.springboot.demo.HelloApplication : Starting HelloApplication on Mr-Lius-Computer with PID 13288 (F:\MyWork\GitHub\LocalGitRepository-Eclipse\itcast-springboot\target\classes started by Weiguo Liu in F:\MyWork\GitHub\LocalGitRepository-Eclipse\itcast-springboot)
2017-11-27 12:51:54.251 INFO 13288 --- [ main] c.i.springboot.demo.HelloApplication : No active profile set, falling back to default profiles: default
2017-11-27 12:51:54.748 INFO 13288 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@62db0cfc: startup date [Mon Nov 27 12:51:54 CST 2017]; root of context hierarchy
2017-11-27 12:51:57.868 INFO 13288 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) //监听8080端口
2017-11-27 12:51:57.890 INFO 13288 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-11-27 12:51:57.892 INFO 13288 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.11 //内核是Tomcat,就是前面说的springboot是内嵌了Tomcat
2017-11-27 12:51:58.125 INFO 13288 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-11-27 12:51:58.125 INFO 13288 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3381 ms
2017-11-27 12:51:58.377 INFO 13288 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] //初始化SpringMVC的dispatcherServlet为“/”,即web项目默认是无项目名,直接访问映射即可,所以上述的应用只需要访问http://localhost:8080/hello即可输出
2017-11-27 12:51:58.383 INFO 13288 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-11-27 12:51:58.383 INFO 13288 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-11-27 12:51:58.383 INFO 13288 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-11-27 12:51:58.383 INFO 13288 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-11-27 12:51:58.891 INFO 13288 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@62db0cfc: startup date [Mon Nov 27 12:51:54 CST 2017]; root of context hierarchy
2017-11-27 12:51:58.988 INFO 13288 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello]}" onto public java.lang.String cn.itcast.springboot.demo.HelloApplication.hello()
2017-11-27 12:51:58.996 INFO 13288 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-11-27 12:51:58.997 INFO 13288 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-11-27 12:51:59.076 INFO 13288 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-27 12:51:59.076 INFO 13288 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-27 12:51:59.142 INFO 13288 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-11-27 12:51:59.571 INFO 13288 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-11-27 12:51:59.740 INFO 13288 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-11-27 12:51:59.748 INFO 13288 --- [ main] c.i.springboot.demo.HelloApplication : Started HelloApplication in 8.239 seconds (JVM running for 9.403)
2017-11-27 12:53:59.515 INFO 13288 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-11-27 12:53:59.515 INFO 13288 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2017-11-27 12:53:59.535 INFO 13288 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 20 ms
4.自定义Banner
第三部启动日志中已经提供对部分做了说明,Spring Boot项目默认的Banner是一个Spring的标志,自己可以百度Banner生成器(比如:http://www.network-science.de/ascii/),输入你想做的Banner字符,然后复制下来保存到本地(比如保存到本地的banner.txt文件),然后将banner.txt文件文件复制到resources目录(即项目中的src/main/resources目录)中即可,下次启动项目的时候会自动加载,比如修改成我姓名的拼音然后按照上述流程启动将会出现下面的Banner
当然也可以关闭这玩意儿,在xxxApplication中的main方法修改成下面的即可
SpringApplication app = new SpringApplication(HelloApplication.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
2.3 Spring Boot的全局配置文件
spring boot项目可以使用一个全局的配置文件指定默认的配置,而且它的名字只能叫做application.properties或者application.yml(推荐使用,较为方便),放到resources目录下。比如:
# 1.application.properties配置,修改Tomcat的端口和映射路径(即此时访问hello的地址就不是上述的localhost:8080/hello而是localhost:8088/hello.html)
server.port=8088
server.servlet-path=*.html
如果使用yml语言配置就是
注意冒号后面一定要加空格
server:
port: 8088
servlet-path: "*.html" #这里配置加了双引号不然报错
当然还有详细的配置选项见https://github.com/Jacksonary/CodeRepository/blob/master/spring-boot-configurationfile.pl
2.4自定springboot的一些默认配置
2.4.1 自定义静态资源位置
# 在全局配置文件中可以指定静态资源的位置spring.resources.static-locations
spring.resources.static-locations=classpath:/public/,classpath:路径2
如果不配置静态文件路径(默认为/)或者进入路径为*.xxx的,那么将静态资源直接放到webapp目录下即可访问
2.4.1自定义消息转换器
这个消息转化器编码是Controller中的return的字符编码问题,不是指jsp页面中的编码
如果页面中文乱码,可以在xxxApplication中加入自定义的消息转换器,默认是UTF-8
自定义消息转化器,只需要在@Configuration的类中添加消息转化器的@Bean到Spring的容器中,就会被Springboot自动加载到容器中
//自动加入SpringMVC的消息转换器中(取代springboot默认的消息转换器),访问页面上如果出现中文乱码,可以把这个代码片加进去
@Bean
public StringHttpMessageConverter stringHttpMessageConverter() {
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
2.4.2自定SpringMVC配置
比如加一个拦截器,这时必须通过继承WebMvcConfigurerAdapter才行,而且这个类必须和xxxApplication类处在同级目录或者其所在目录的子目录下面才能被扫描。下面是简单的实现代码
package cn.itcast.springboot.demo;
import java.nio.charset.Charset;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration //申明这是一个配置
public class MySpringMVCConfig extends WebMvcConfigurerAdapter{
// 自定义拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
HandlerInterceptor handlerInterceptor = new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("自定义拦截器............");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
}
};
//其中/**表示所有的请求都会经过这个自定的拦截器
registry.addInterceptor(handlerInterceptor).addPathPatterns("/**");
}
// 自定义消息转化器的第二种方法
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
converters.add(converter);
}
}
3.Spring Boot项目中JSP页面无法访问的问题
由于Spring Boot中是内嵌Tomcat的,但是注意这个Tomcat是不支持jsp页面的,必须导入相应的依赖才能访问。
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
4.发布Spring Boot项目到独立的Tomcat中(即实际生产环境中)
1.工程打包方式为war
这一点可以在创建Spring Starter Project时指定packaging类型为war而不是jar
2.设置spring-boot-starter-tomcat依赖的作用域
将spring-boot-starter-tomcat的作用域设置为provided,表示在工程打包时会自动排除这个依赖,使用生产环境中Tomcat而不是使用SpringBoot中内嵌的Tomcat,没有一定要加上(很多情况因为传递依赖并没有显式的表现出来)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
3.修改代码,设置启动配置
让启动类继承SpringBootServletInitializer,重写其中的configure()方法,将Spring Boot的入口类设置进去。如下代码片
public class HelloApplication extends SpringBootServletInitializer {
......
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//设置启动类,用于独立Tomcat的运行入口
return builder.sources(HelloApplication.class);
}
......
}
4.打包工程
1.打包成war包
右击项目–>Run As–>Run Configurations–>在Goals中输入命令:clean package,勾选Skip Tests–>Run即可。
这样即可打包war包,丢到Tomcat中的webapp目录下即可,运行访问会自动解压,即使没有web.xml文件,但是Spring Boot项目在第三步继承了SpringBootServletInitializer类在打包的时候会自动写一些启动类,所以不必再写web.xml文件
2.打包成jar包
因为上述建工程的时候直接选了packaging为war,所以不需要动,如果要打包成jar包,在pom.xml需要进行修改,将packaging标签改成jar
<packaging>jar</packaging>
然后执行打包命令:Run As–>Maven install即可,打包好的jar包就在项目target目录下面。运行的时候,在dos窗口下,切换到jar包所在目录,执行以下命令即可运行jar包
java -jar jar包
如下