SpringBoot

1 SpringBoot入门

1.1 创建SpringBoot项目

alt

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

alt alt

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

alt

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-*都包含依赖 alt

<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);
        }
    }
}

alt

3.2 扫描路径

  • 默认路径:启动类所在包及其子包,默认扫描pack包+controller。 alt
@ComponentScans(@ComponentScan("xyz.liu76"))
@SpringBootApplication
public class PackApplication {
  • 扫描到的Controller会自动配置。 alt

3.3 自动配置原理

3.3.1 @SpringBootApplication

alt @SpringBootConfiguration 标记当前类为配置类 @EnableAutoConfiguration 开启自动配置
@ComponentScan 默认扫描当前包下所有组件

3.3.2 @EnableAutoConfiguration

自动配置包 @Import(AutoConfigurationImportSelector.class)直接导入一个组件
@AutoConfigurationPackage 负者导入的包内的组件 alt

@Import(AutoConfigurationImportSelector.class) 导入AutoConfigurationImportSelector组件,selectImports(AnnotationMetadata)方法--返回带有@Configuration的注解的类名。 getAutoConfigurationEntry(AnnotationMetadata)给容器批量导入组件 alt

getCandidateConfigurations(AnnotationMetadata,AnnotationAttributes) 返回所有自动配置列表 alt

SpringFactoriesLoader._loadFactoryNames()_返回工厂加载所有配置列表 alt

加载配置文件,每个模块的接口作为key,实现类作为value。 alt

alt alt

3.3.4 @AutoConfigurationPackage

包路径下批量注册组件 alt

AnnotationMetadata 注解元信息,存放注解的位置、值 alt

new PackageImports(metadata).getPackageNames()获取注解所在的包名 注册包名下所有组件导入 alt

3.3.5 按需配置

  1. Web配置
    多个Condition条件注入方式,如果存在DispatcherServlet.class,才导入配置。SpringBoot全面接管SpringMVC配置 alt alt

  2. 编码配置
    @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));
}

alt

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));
    
}

alt

4.2 @Import

@Import({User.class})//注册到容器中一个全类名的对象
@Configuration(proxyBeanMethods = true)
public class MyConfig {
    @Bean("myUser")
    public User getUser(){
        return new User("aaa","123");
    }
}

alt

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");
    }
}

alt

获取myUser的Bean失败 alt

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");
    }
}

alt

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 静态资源

alt

默认静态路径,localhost:8066/xxx.jpg
/static
/public
/resources
/META-INF/resources

altalt

5.1.1 静态资源路径配置

alt

修改静态文件默认路径:
spring.web.resources.static-locations=classpath:/xxx/

修改后,所有默认静态路径都会失效。 alt

5.1.2 静态资源与动态请求

静态映射默认拦截:/**,所有的请求。 原理:先去Controller匹配,再去静态资源路径匹配,没有就返回404.

5.1.3 访问路径前缀配置

配置拦截路径/res/**,只会拦截带有res的url 导致index与favicon失效 alt alt

直接在配置的默认静态路径下,创建文件 alt

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请求。 alt

<form action="..." method="post">
        <input type="hidden" name="_method" value="put" />
        ......
</form>

5.3.2 WebMVC配置适配器组件

两个配置文件绑定,绑定application.properties中的配置参数。
WebMvcProperties:alt

WebProperties:alt

alt

当配置类只有一个有参构造器,所有参数值都会从容器中确定。

//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 静态资源路径配置

  1. this.resourceProperties.isAddMappings() 判断是否开启静态资源映射 alt
    false后,所有静态资源都不能访问。

  2. addResourceHandler() 添加资源处理器 alt 三个参数:
    registry,映射url,静态资源路径
    this.mvcProperties.getStaticPathPattern() 默认配置静态资源映射路径。 this.resourceProperties.getStaticLocations()获取配置文件中资源路径 alt alt

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务