• xxxxAutoConfiguration :向容器中添加自动配置组件
  • xxxxProperties :使用自动配置类 来封装 配置文件的内容

SpringMVC配置 : WebMvcAutoConfiguration 和 WebMvcProperties

内嵌 Servlet 容器 : ServletWebServerFactoryAutoConfiguration 和 ServerProperties

上传文件的属性 :MultipartAutoConfiguration 和 MultipartProperties

JDBC : DataSourceAutoConfiguration 和 DataSourceProperties

对静态资源的映射规则, 可通过分析 WebMvcAutoConfiguration 自动配置类得到

Springboot默认的静态资源目录

  1. src/main/resources/目录下创建 static文件夹
  2. src/main/resources/目录下创建 resources文件夹
  3. src/main/resources/目录下创建 public文件夹
  4. src/main/resources/目录下创建 META-INF/resources文件夹

如果每个目录下面都有相同的文件,那么访问的优先级为 META-INF>resources>static>public

图标映射

  • Spring Boot 会在静态资源目录下 与 根路径(按该顺序) 查找 faicon.ico 页面;如果存在这样的文件,Spring Boot 会自动将其设置为应用图标。

  • classpath:/META-INF/resources/

  • classpath:/resources/

  • classpath:/static/

  • classpath:/public/

  • /: 当前项目根路径下

静态资源的映射规则

  • 对静态资源的映射规则, 可通过分析 WebMvcAutoConfiguration 自动配置类得到
    1. org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addResourceHandlers
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
    } else {
        this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
        this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
            // 获取静态资源
            registration.addResourceLocations(this.resourceProperties.getStaticLocations());
            if (this.servletContext != null) {
                ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                registration.addResourceLocations(new Resource[]{resource});
            }

        });
    }
}

 public static class Resources {
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
}
  1. org.springframework.boot.autoconfigure.web.WebProperties.Resources

Thymeleaf 模板引擎

引入 Thymeleaf

pom.xml 加入 Thymeleaf 启动器

 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>

  • ThymeleafProperties
  • 导入 Thymeleaf 的名称空间 在 html 页面加上以下名称空间, 使用 Thymeleaf 时就有语法提示。 <html xmlns:th="http://www.thymeleaf.org">
    • 开发环境下关闭thymeleaf模板缓存,thymeleaf默认是开启状态 spring.thymeleaf.cache=false

SpringBoot 热部署

  • 在Intellij IEDA 中,修改文件后都是自动保存,默认不会自动编译文件, 需要手动编译按 Ctrl + F9 (推荐使用)或 Build -> Build Project
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-devtools</artifactId>
 </dependency>

注册Servlet三大组件

Servlet/Filter/Listener

  • 而由于 Spring Boot 默认是以 jar 包的方式运行嵌入式Servlet容器来启动应用,没有web.xml文件,Spring提供以下Bean来注册三大组件:
    • ServletRegistrationBean :注册自定义Servlet
    • FilterRegistrationBean :注册自定义Filter
    • ServletListenerRegistrationBean :注册自定义Listener

 //注册Filter组件
 @Configuration
 public class MyFilterConfig {
    //注册Filter组件
    @Bean
    public FilterRegistrationBean myFilter() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        //指定过滤器
        bean.setFilter(new MyFilter());
        //过滤哪些请求
        bean.setUrlPatterns(Arrays.asList("/hello"));
        return bean;
    }
 }

 //监听应用启动与销毁
 public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("SpringBoot.Servlet应用启动");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("SpringBoot.Servlet应用销毁");
    }
 }


@Configuration
public class MyServletConfig {
    //注册Listener
    @Bean
    public ServletListenerRegistrationBean myListener() {
        return new ServletListenerRegistrationBean(new MyListener());
    }
}

SpringBoot 错误处理机制

  • 底层原理分析 ErrorProperties

  • 底层原理关注 ErrorMvcAutoConfiguration 错误自动配置类

  • 第1步: ErrorPageCustomizer 错误页面定制器

static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
private final ServerProperties properties;
private final DispatcherServletPath dispatcherServletPath;

protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
this.properties = properties;
this.dispatcherServletPath = dispatcherServletPath;
}

public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
// 出现错误后来到 /error 请求进行处理(类似web.xml注册的错误页面规则)
this.properties.getError().getPath())); //private String path = "/error";

ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
errorPageRegistry.addErrorPages(new ErrorPage[]{errorPage});
}

public int getOrder() {
return 0;
}
}
  • 当应用出现了4xx或5xx之类的错误 ,ErrorPageCustomizer就会被激活,它主要 用于定制错误 处理的响应规则,
  • 就会发送一个/error请求,它会交给 BasicErrorController进行处理
  • BasicErrorController 就会接收 /error 请求处理
  • BasicErrorController 会接收一个/error请求, 两个 方法处理,第1个erroHtml响应html数据, 还有一个error用来响应json数据 的, 使用了 ErrorViewResolver (DefaultErrorViewResolver) 组件进行封装视图

springboot2版本无法加载静态资源问题解决

  • 默认加载路径

首先得知道springboot默认加载得资源路径是什么。

首先我们看org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration这个类。里面有一个方法叫做addResourceHandlers()

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
    ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
        @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
      if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
        return;
      }
      Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
      CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
      
      //所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源
      if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/")
            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
      }
      
      //静态资源文件夹映射
      //  org.springframework.boot.autoconfigure.web.WebProperties
      String staticPathPattern = this.mvcProperties.getStaticPathPattern();
      if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
            .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
            .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
      }
    }
}
  1. 首先springboot会将我们classpath:/META-INF/resources/webjars/路径下的文件映射为/webjars/**

  2. 然后再一个if判断进行静态资源文件夹映射,首先判断我们是否以使用 "/**" 做映射

  3. 如果没有,则将 "/**" 访问当前项目的任何资源,都去(如下静态资源的文件夹)找映射

容易出问题的地方

全面控制 SpringMVC

  • 如果你想全面控制SpringMVC(SpringBoot对SpringMVC的自动配置都废弃), 在自定义的Web配置类上添加 @Configuration 和 @EnableWebMvc 注解。

为什么添加 @EnableWebMvc 自动配置就失效了?

  1. @EnableWebMvc 的核心
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}

  1. 先记住继承了WebMvcConfigurationSupport类
  2. 而在 WebMvcAutoConfiguration 上使用了 **@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)**
  • 有些时候 代码中,直接访问静态资源却无法做映射
  • 仔细看看WebMvcAutoConfiguration这个类。在其头上有一个这个注解: @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@Configuration
public class CorsConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addCorsMappings(CorsRegistry registry) {
        super.addCorsMappings(registry);
        registry.addMapping("/**")
                .allowedMethods("*")
                .allowedOrigins("*")
                .allowedHeaders("*");
    }
}
  1. 继承了WebMvcConfigurationSupport这个类,使得springboot的自动装配失效了。

  2. 因为 @ConditionalOnMissingBean 这个注解得作用就是,当容器中不存在这个类,如下得代码才有作用。

  3. 有时候我们得项目并不希望springboot给我们自动装配。希望完全由我们自己来配置自己来掌握。

  4. 要想达到这个效果,springboot给我们提供了一个更为简洁得方式。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
// @EnableWebMvc注解会导入DelegatingWebMvcConfiguration.clss
// 而DelegatingWebMvcConfiguration又继承了WebMvcConfigurationSupport
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}
// 所以当我们加上@EnableWebMvc也会有同样得效果且简洁。

事务的隔离级别和传播行为

除了指定事务管理器之后,还能对事务进行隔离级别和传播行为的控制,下面分别详细解释:

  • 隔离级别 隔离级别是指在发生并发的事务之间的隔离程度,与我们开发时候主要相关的场景包括:脏读、不可重复读、幻 读。
    • 脏读:A事务执行过程中修改了id=1的数据,未提交前,B事务读取了A修改的id=1的数据,而A事务却回滚了,这 样B事务就形成了脏读。
    • 不可重复读:A事务先读取了一条数据,然后执行逻辑的时候,B事务将这条数据改变了,然后A事务再次读取的时 候,发现数据不匹配了,就是所谓的不可重复读了。
    • 幻读:A事务先根据条件查询到了N条数据,然后B事务新增了M条符合A事务查询条件的数据,导致A事务再次查询 发现有N+M条数据了,就产生了幻读;
package org.springframework.transaction.annotation;
// spring  中的 事务隔离级别
public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);

    private final int value;

    private Isolation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

  • READ_UNCOMMITTED :该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级 别不能防止脏读和不可重复读,因此很少使用该隔离级别。
  • READ_COMMITTED :该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏 读,这也是大多数情况下的推荐值,性能最好。
  • REPEATABLE_READ :该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回 的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可 以防止脏读和不可重复读。
  • SERIALIZABLE :所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可 以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 指定方式:通过使用 isolation 属性设置,例如:@Transactional(isolation=Isolation.DEFAULT)