欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Spring Boot启动过程中的自动配置:WebMvcAutoConfiguration、MessageSourceAutoConfiguration与ErrorMvcAutoConfiguration详解

最编程 2024-02-18 08:29:35
...

WebMvcAutoConfiguration : webmvc自动化配置

MessageSourceAutoConfiguration  :国际化自动配置

ErrorMvcAutoConfiguration:统一异常处理自动配置

 

 

官网解释:https://docs.spring.io/spring-boot/docs/3.0.9/reference/html/features.html#features.developing-auto-configuration.condition-annotations

从其他博客粘过来的表格:

条件注解 Condition处理类 实例 解释
@ConditionalOnBean OnBeanCondition @ConditionalOnBean(DataSource.class) Spring容器中不存在对应的实例生效
@ConditionalOnMissingBean OnBeanCondition @ConditionalOnMissingBean(name = "redisTemplate") Spring容器中不存在对应的实例生效
@ConditionalOnSingleCandidate OnBeanCondition @ConditionalOnSingleCandidate(FilteringNotifier.class)

Spring容器中是否存在且只存在一个对应的实例,

或者虽然有多个但 是指定首选的Bean生效

@ConditionalOnClass OnClassCondition @ConditionalOnClass(RedisOperations.class) 类加载器中存在对应的类生效
@ConditionalOnMissingClass OnClassCondition @ConditionalOnMissingClass(RedisOperations.class) 类加载器中不存在对应的类生效
@ConditionalOnExpression OnExpressionCondition @ConditionalOnExpression(“’${server.host}’==’localhost’”) 判断SpEL 表达式成立生效
@ConditionalOnJava OnJavaCondition @ConditionalOnJava(JavaVersion.EIGHT) 指定Java版本符合要求生效
@ConditionalOnProperty OnPropertyCondition

@ConditionalOnProperty(prefix = “spring.aop”, name = “auto”,

havingValue = “true”, matchIfMissing = true)

应用环境中的属性满足条件生效
@ConditionalOnResource OnResourceCondition @ConditionalOnResource(resources=”mybatis.xml”) 存在指定的资源文件生效
@ConditionalOnWebApplication OnWebApplicationCondition   当前应用是Web应用生效
@ConditionalOnNotWebApplication OnWebApplicationCondition   当前应用不是Web应用生效

       上面的扩展注解我们可以简单的分为以下几类:

  • Bean作为条件:@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnSingleCandidate。
  • 类作为条件:@ConditionalOnClass、@ConditionalOnMissingClass。
  • SpEL表达式作为条件:@ConditionalOnExpression。
  • JAVA版本作为条件: @ConditionalOnJava
  • 配置属性作为条件:@ConditionalOnProperty。
  • 资源文件作为条件:@ConditionalOnResource。
  • 是否Web应用作为判断条件:@ConditionalOnWebApplication、@ConditionalOnNotWebApplication。

以上是理解springboot默认加载的基础。

1.

 2.

 3.

 4.

 5.

 6.

 7.截图放不下了,最终会指向 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

 8. imports 局部截图。这里包含了springboot想为你加载的所有模块的 *AutoConfiguration

 9.当然,这些自动配置类并不是全部都会用到,会经过筛选处理

 10.现在我们看一下 WebMvcAutoConfiguration.. 如果满足这三个条件。就不会过滤掉,看看上面的筛选条件。

 11.看看WebMvcAutoConfiguration 做了什么。 根据条件注解,看看加载 Bean的条件,。思考如何定义自己的 bean并替换它们吧!

 


 

 12.自定义 WebMvcConfigurer 进行 默认配置类的扩展。这里代码仅供参考,主要讨论扩展原理

//@EnableWebMvc    加了这个会使Springmvc自动配置失效
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    /**
     * 添加视图控制器
     * 立即访问
     * <mvc:view-controller path="/" view-name="index" />
     *
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/tuling").setViewName("hello");
    }

    /**
     * 添加拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TimeInterceptor())     //添加拦截器
                .addPathPatterns("/**")    // 拦截映射规则
                .excludePathPatterns("/pages/**");  // 设置排除的映射规则

        // 添加国际化拦截器
        registry.addInterceptor(new LocaleChangeInterceptor())
                .addPathPatterns("/**");    // 拦截映射规则
    }

    /**
     * 全局CORS配置
     *
     * @param
     * @Override public void addCorsMappings(CorsRegistry registry) {
     * registry.addMapping("/user/*")   // 映射服务器中那些http接口运行跨域访问
     * .allowedOrigins("http://localhost:8081")     // 配置哪些来源有权限跨域
     * .allowedMethods("GET","POST","DELETE","PUT");   // 配置运行跨域访问的请求方法
     * }
     */


    @Bean
    public LocaleResolver localeResolver() {
        CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
        // 可以设置过期时间
        cookieLocaleResolver.setCookieMaxAge(60 * 60 * 24 * 30);
        cookieLocaleResolver.setCookieName("locale");
        return cookieLocaleResolver;
    }
}
代码仅供参考

13.书接前文,还是在 WebMvcAutoConfiguration 里 

WebMvcAutoConfigurationAdapter 通过
@Import(EnableWebMvcConfiguration.class) 导入 EnableWebMvcConfiguration 
EnableWebMvcConfiguration 继承了 DelegatingWebMvcConfiguration

 14。

DelegatingWebMvcConfiguration作为一个配置类,将容器里所有的 webMvcConfigurer 全部注入进了 configurers.
注意:重写的 WebMvcConfigurationSupport 方法,都是在处理 configurers

 15. @EnableWebMvc. 是自动配置失效的原理

注意:13步里的 Configuration equivalent to @EnableWebMvc.

 如下图:没有 WebMvcConfigurationSupport 类 WebMvcAutoConfiguration 才会生效 

而 @EnableWebMvc注解导入的 DelegatingWebMvcConfiguration 继承自 WebMvcConfigurationSupport 
所以 添加 @EnableWebMvc 后 WebMvcAutoConfiguration 自动配置就会失效

 


 

 16.国际化自动配置类 MessageSourceAutoConfiguration 配置国际化资源文件

springmvc下的配置:

    <!--设置国际化支持,配置国际化资源文件 id="messageSource“不能乱取名-->
    <bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
        <!--setBaseNames()-->
        <property name="basenames">
            <array>
                <value>i18n.logion</value>
            </array>
        </property>
    </bean>

springboot下的自动配置:

 

只有资源存在,这个国际化配置类才会生效:

 所以,这里就有两种方式了:

方式一:自定义文件夹,添加 spring.messages.basename 配置

方式二: 放入指定的 messages文件夹:

 这是自动配置类生效,才会为我们配置 MessageSource

 17. LocaleResolver 的自动化配置

之前springmvc 对比配置

    <!--设置国际化支持,配置国际化资源文件 id="messageSource“不能乱取名-->
    <bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
        <!--setBaseNames()-->
        <property name="basenames">
            <array>
                <value>i18n.logion</value>
            </array>
        </property>
    </bean>
    <!--    使用SessionLocaleResolver,保持local状态,会从session中获取local对象 id="localeResolver"只能叫localeResolver,为了覆盖springmvc默认AcceptHeaderLocaleResolver
         不配制的话默认使用的是 AcceptHeaderLocaleResolver,会从请求头里获取“Aceept-Language”
         国际化二:SessionLocaleResolver 替换默认的 AcceptHeaderLocaleResolver
    -->
    <bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver" id="localeResolver"></bean>
<!-- 不实用AcceptHeaderLocaleResolver 是因为每次请求都要判断 都要Accept-Language 为空才使用配置语言-->
<!-- <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver" id="localeResolver"></bean>-->
 

而在 WebMvcAutoConfiguration 自动配置类里,springboot也帮我们配好了

 注意:

 可以通过进行配置,来选择时固定使用某一语言还是从头里去取

旧版本是这么写的,新版本已经弃用了,转为 spring.web.locale-resolver

 18: 

AcceptHeaderLocaleResolver局限性是每次请求都会判断 Accept-Language 。没有才会使用默认配置。所以我们之前使用

org.springframework.web.servlet.i18n.SessionLocaleResolver
所以我们还是要自定义localeResolver

 19.自定义 localeResolver  查看12步的参考代码里有

 


 

20.统一异常处理自动配置,

官网说明:https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.servlet.spring-mvc.error-handling

统一配置类 ErrorMvcAutoConfiguration

 

 

BasicErrorController 下面定义的处理接口

 在errorHtml ()里调用的resolveErrorView()里使用的就是 DefaultErrorAttributes

 

总结: 从errorHtml方法可以得出结论: 我们需要使用自定义的页面响应错误只需要在对应的路径上创建对应错误代码的页面就行了,, 但是如果想记录日志就需要自己定制了。

 对于ajax请求的error处理,没办法更改,只能自定义类实现  AbstractErrorController 去替换 BasicErrorController 的自动配置 自己去实现 error()处理

@Controller
@RequestMapping("/error")
public class CustomErrorController extends AbstractErrorController {
    public CustomErrorController(ErrorAttributes errorAttributes, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, errorViewResolvers);
    }

    Logger logger = LoggerFactory.getLogger(CustomErrorController.class);

    /**
     * 处理浏览器请求的
     * 加上异常日志记录
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections
                .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions()));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        logger.error(model.get("trace").toString());
        return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    }

    /**
     * 处理ajax
     * 修改返回类型:Result 完成
     * 加上异常日志记录
     *
     * @param request
     * @return
     */
    @RequestMapping
    @ResponseBody
    public Result error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new Result(204, "No Content");
        }

        Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions());
        String code = body.get("status").toString();
        String message = body.get("message").toString();
        logger.error(body.get("trace").toString());
        return new Result(Integer.parseInt(code), message);
    }


    /**
     * 异常信息的选项
     *
     * @return
     */
    protected ErrorAttributeOptions getErrorAttributeOptions() {
        ErrorAttributeOptions of = ErrorAttributeOptions.of(ErrorAttributeOptions.Include.MESSAGE,
                ErrorAttributeOptions.Include.STACK_TRACE,
                ErrorAttributeOptions.Include.EXCEPTION);
        return of;
    }


    @Override
    public String getErrorPath() {
        return null;
    }
}
自定义参考代码

 当然,异常处理还可以使用 

@ControllerAdvice
@ExceptionHandler
这个更加灵活,在这里只为分析springboot的自动配置以及根据他的自动配置进行定制。所以这两个注解不再这里的讨论范围内