SpringBoot
1 SpringBoot入门
1.1 创建SpringBoot项目
1.2 导入Web模块依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
1.3 打包jar包
1.3.1 修改生成后jar包名字
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!--jar包生成后的名字-->
<finalName>packApplication-service-${version}</finalName>
</build>
1.3.2 跳过打包测试
<properties>
<java.version>1.8</java.version>
<!--跳过测试-->
<maven.test.skip>true</maven.test.skip>
</properties>
1.3.3 执行命令mvn package
1.4 Linux下运行jar包
1.4.1 编写可执行脚本
- xxx.sh文件
#!/bin/bash
# nohub 后台运行,命令执行的同级目录下生成日志
# -server jvm开启server模式生产环境,性能比client模式高
# metaspaceSize 元空间大小
# Xms 初始堆内存
# Xmx 最大堆内存
# Xmn 新生代堆内存
# Xss 栈的大小,即线程的使用内存大小。设置小,生成线程多,容易内存溢出;设置大 影响线程创建数量。
# -XX:SurvivorRatio 新生代中Eden区与两个Survivor区的比值。8:1:1
# -XX:UseConcMarkSweepGC 并发垃圾回收器
nohup java -server -jar -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms64m -Xmx128m -Xmn64m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -jar "$1" > "$1.log" 2>&1 &tail -1000f "$1.log"
1.4.2 jar包执行命令
./xxx.sh packApplication-service-0.0.1-SNAPSHOT.jar
2 依赖管理
Each release of Spring Boot provides a curated list of dependencies that it supports. In practice, you do not need to provide a version for any of these dependencies in your build configuration, as Spring Boot manages that for you. When you upgrade Spring Boot itself, these dependencies are upgraded as well in a consistent way.
You can still specify a version and override Spring Boot’s recommendations if you need to do so. |
---|
The curated list contains all the Spring modules that you can use with Spring Boot as well as a refined list of third party libraries. The list is available as a standard Bills of Materials (spring-boot-dependencies) that can be used with both Maven and Gradle.
Each release of Spring Boot is associated with a base version of the Spring Framework. We highly recommend that you not specify its version. |
---|
2.1 项目依赖
<!--创建的项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--父项目依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
spring-boot-dependencies中依赖包
<properties>
<activemq.version>5.15.12</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.80</appengine-sdk.version>
<artemis.version>2.12.0</artemis.version>
<aspectj.version>1.9.5</aspectj.version>
</properties>
2.2 starter场景启动器
每个spring-boot-starter-*都包含依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.0.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
2.3 覆盖默认版本号
创建的项目中
<properties>
<java.version>1.8</java.version>
<mysql.version>8.0.10</mysql.version>
<maven.test.skip>true</maven.test.skip>
</properties>
3 自动配置
3.1 自动配置查看
@SpringBootApplication
public class PackApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(PackApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
//打印自动配置加载的类
System.out.println(beanDefinitionName);
}
}
}
3.2 扫描路径
- 默认路径:启动类所在包及其子包,默认扫描pack包+controller。
@ComponentScans(@ComponentScan("xyz.liu76"))
@SpringBootApplication
public class PackApplication {
- 扫描到的Controller会自动配置。
3.3 自动配置原理
3.3.1 @SpringBootApplication
@SpringBootConfiguration 标记当前类为配置类
@EnableAutoConfiguration 开启自动配置
@ComponentScan 默认扫描当前包下所有组件
3.3.2 @EnableAutoConfiguration
自动配置包
@Import(AutoConfigurationImportSelector.class)直接导入一个组件
@AutoConfigurationPackage 负者导入的包内的组件
@Import(AutoConfigurationImportSelector.class)
导入AutoConfigurationImportSelector组件,selectImports(AnnotationMetadata)方法--返回带有@Configuration的注解的类名。
getAutoConfigurationEntry(AnnotationMetadata)给容器批量导入组件
getCandidateConfigurations(AnnotationMetadata,AnnotationAttributes) 返回所有自动配置列表
SpringFactoriesLoader._loadFactoryNames()_返回工厂加载所有配置列表
加载配置文件,每个模块的接口作为key,实现类作为value。
3.3.4 @AutoConfigurationPackage
包路径下批量注册组件
AnnotationMetadata 注解元信息,存放注解的位置、值
new PackageImports(metadata).getPackageNames()获取注解所在的包名
注册包名下所有组件导入
3.3.5 按需配置
-
Web配置
多个Condition条件注入方式,如果存在DispatcherServlet.class,才导入配置。SpringBoot全面接管SpringMVC配置 -
编码配置
@EnableConfigurationProperties(ServerProperties.class)配置绑定
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
//默认开启
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
//获取配置文件的值,设置到本类配置
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
//容器中没有才自动配置
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}
3.4 配置文件属性
https://docs.spring.io/spring-boot/docs/2.6.2/reference/htmlsingle/#application-properties
4 常用注解详解
4.1 @Configuration
4.1.1 Full模式
外部调用配置类组件注册方法,都是返回容器中的单实例对象。 默认情况下:@Configuration(proxyBeanMethods = true)
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean("myUser")
public User getUser(){
return new User("aaa","123");
}
}
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(PackApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
MyConfig myConfig = run.getBean("myConfig", MyConfig.class);
User user1 = myConfig.getUser();
User user2 = myConfig.getUser();
//多次调用getUser(),会先去容器检查是否存在,如果容器中存在,每次都返回容器中的User对象
System.out.println("user1 == user2===>" + (user1==user2));
}
4.1.2 Lite模式
外部调用配置类组件注册方法,都是直接执行注册方法。 @Configuration(proxyBeanMethods = false)
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean("myUser")
public User getUser(){
return new User("aaa","123");
}
}
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(PackApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
MyConfig myConfig = run.getBean("myConfig", MyConfig.class);
User user1 = myConfig.getUser();
User user2 = myConfig.getUser();
//多次调用getUser(),不会去检查容器,直接返回方法的返回值。
System.out.println("user1 == user2===>" + (user1==user2));
}
4.2 @Import
@Import({User.class})//注册到容器中一个全类名的对象
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean("myUser")
public User getUser(){
return new User("aaa","123");
}
}
4.2.1 @ImportResources
导入配置文件
@Configuration
@ImportResource("classpath:bean.xml")
public class MyConfig {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="UserBean" class="xyz.liu76.pack.pojo.UserBean">
<property name="id" value="1"></property>
</bean>
</beans>
4.3 @ConditionalOnBean
条件注入Bean
@Import({User.class})
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean("myUser")
@ConditionalOnBean(name={"xyz.liu76.pack.pojo.User12"})
//当name=xyz.liu76.pack.pojo.User12时bean存在
public User getUser(){
return new User("aaa","123");
}
}
获取myUser的Bean失败
4.4 @ControllerAdvice
全局异常处理
4.4.1 @ExceptionHandler
进行全局的 Controller 层异常处理。
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(Exception.class)
public DataResult handleException(Exception e){
return DataResult.getResult(BaseResponseCode.SYSTEM_ERROR);
}
/**
* 被除数0 异常
* @param e
* @return
*/
@ExceptionHandler(ArithmeticException.class)
public DataResult arithmeticException(ArithmeticException e){
return DataResult.getResult(BaseResponseCode.BY_ZERO_ERROR);
}
}
4.4.2 DataResult
@Data
public class DataResult<T> {
@ApiModelProperty("响应状态码")
private int code;
@ApiModelProperty("响应提示")
private String msg;
@ApiModelProperty("响应数据")
private T data;
public DataResult(int code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public DataResult(int code, String msg) {
this.code = code;
this.msg = msg;
}
public DataResult(ResponseCodeInterface responseCodeinterface){
this.code=responseCodeinterface.getCode();
this.msg=responseCodeinterface.getMsg();
this.data=null;
}
public DataResult(ResponseCodeInterface responseCodeinterface,T data){
this.code=responseCodeinterface.getCode();
this.msg=responseCodeinterface.getMsg();
this.data=data;
}
/**
* 操作成功,data为null
*/
public DataResult(){
this.code= BaseResponseCode.SUCCESS.getCode();
this.msg=BaseResponseCode.SUCCESS.getMsg();
this.data=null;
}
/**
* 请求成功,返回data
* @param data
*/
public DataResult(T data){
this.code=BaseResponseCode.SUCCESS.getCode();
this.msg=BaseResponseCode.SUCCESS.getMsg();
this.data=data;
}
/**
* 自定义返回,无需data
* @param code 响应状态码
* @param msg 响应提示语
* @return
*/
public static DataResult getResult(int code, String msg){
return new DataResult(code,msg);
}
/**
* 自定义data返回
* @param code 响应状态码
* @param msg 响应提示语
* @param data 响应数据
* @param <T>
* @return DataResult
*/
public static <T> DataResult getResult(int code, String msg, T data){
return new DataResult(code,msg,data);
}
/**
* 自定义返回,一般返回异常时调用,data为null
* @param baseResponseCode
* @return
*/
public static DataResult getResult(BaseResponseCode baseResponseCode){
return new DataResult(baseResponseCode);
}
/**
* 自定义返回,一般返回异常时调用
* @param baseResponseCode
* @param data
* @param <T>
* @return
*/
public static <T> DataResult getResult(BaseResponseCode baseResponseCode,T data){
return new DataResult(baseResponseCode,data);
}
/**
* 请求成功时调用,data为null
* @return
*/
public static DataResult success(){
return new DataResult();
}
/**
* 请求成功,需要返回data
* @param data
* @param <T>
* @return
*/
public static <T> DataResult success(T data){
return new DataResult(data);
}
}
4.4.3 Controller
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping("/login")
public DataResult<String> login(){
int i=1/0;
return DataResult.success("123");
}
}
4.5 @ConfigurationProperties
配置绑定,前提:容器中的组件
@Component("user3")
//或者@EnableConfigurationProperties({UserConfigProperties.class})
@ConfigurationProperties(prefix = "user")//绑定配置文件值
@Data
public class UserConfigProperties {
String name;
String age;
}
main方法——获取Bean
ConfigurableApplicationContext run = SpringApplication.run(PackApplication.class, args);
System.out.println(run.getBean("user3"));
user.name="llll"
user.age="111"
5 Web模块
5.1 静态资源
默认静态路径,localhost:8066/xxx.jpg
/static
/public
/resources
/META-INF/resources
5.1.1 静态资源路径配置
修改静态文件默认路径:
spring.web.resources.static-locations=classpath:/xxx/
修改后,所有默认静态路径都会失效。
5.1.2 静态资源与动态请求
静态映射默认拦截:/**,所有的请求。 原理:先去Controller匹配,再去静态资源路径匹配,没有就返回404.
5.1.3 访问路径前缀配置
配置拦截路径/res/**,只会拦截带有res的url
导致index与favicon失效
直接在配置的默认静态路径下,创建文件
5.3 WebMvc自动配置
@Configuration(proxyBeanMethods = false) 表示配置类
@ConditionalOnWebApplication(type = Type.SERVLET) 只基于Servlet类型匹配
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) 存在这些类时启用自动配置
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 当不存在这个组件时启用
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) Bean定义顺序,优先定义
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
5.3.1表单PUT请求提供组件
//处理Form表单put、delete请求的过滤器
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
POST提交表单,采用一个默认参数,处理put、delete请求。
<form action="..." method="post">
<input type="hidden" name="_method" value="put" />
......
</form>
5.3.2 WebMVC配置适配器组件
两个配置文件绑定,绑定application.properties中的配置参数。
WebMvcProperties:
WebProperties:
当配置类只有一个有参构造器,所有参数值都会从容器中确定。
//WebMvcAutoConfigurationAdapter类的构造函数
public WebMvcAutoConfigurationAdapter(
WebProperties webProperties, 获取spring.web配置参数绑定的对象
WebMvcProperties mvcProperties,获取spring.mvc配置参数绑定的对象
ListableBeanFactory beanFactory, 获取bean工厂
ObjectProvider<HttpMessageConverters> messageConvertersProvider, 获取所有HttpMessageConverters
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, 找自定义资源处理器
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) 给应用注册servlet、Filter
{
}
5.3.2.1 静态资源路径配置
-
this.resourceProperties.isAddMappings() 判断是否开启静态资源映射
false后,所有静态资源都不能访问。 -
addResourceHandler() 添加资源处理器
三个参数:
registry,映射url,静态资源路径
this.mvcProperties.getStaticPathPattern() 默认配置静态资源映射路径。 this.resourceProperties.getStaticLocations()获取配置文件中资源路径