Примечания к исследованию Spring Boot 02 — глубокое понимание автоматической настройки

Spring Boot задняя часть Spring Tomcat

Резюме

После прочтения этой статьи у вас будут следующие очки знаний:

  1. Какую автоматическую настройку нам помогает сделать SpringBoot?
  2. Как мы можем взять на себя автоматическую настройку SpringBoot
  3. Методы регистрации Servlet, Filter и Listener

серия SpringBoot:Заметки об исследовании Spring Boot


Автоматическая настройка SpringBoot

1. Классы автоматической конфигурации хранятся вspring-boot-autoconfigure-1.4.2.RELEASE.jarвниз
org.springframework.boot.autoconfigureпод дорожкой;
2.Настройка в application.propertiesdebug=trueПосле запуска контейнера видно, что автоматическая настройка инициализации сервера выглядит следующим образом:

  • DispatcherServletAutoConfiguration
    регистрorg.springframework.web.servlet.DispatcherServlet
  • EmbeddedServletContainerAutoConfiguration
    Зарегистрируйте тип контейнера, если он существует в пути к классам.org.apache.catalina.startup.Tomcat, контейнер Tomcat будет зарегистрирован
  • ErrorMvcAutoConfiguration
    Зарегистрировать обработчик исключений
  • HttpEncodingAutoConfiguration
    Зарегистрировать фильтр кодирования http
  • HttpMessageConvertersAutoConfiguration
    Зарегистрируйте процессор json или xml
  • JacksonAutoConfiguration
    Зарегистрировать парсер объектов json
  • JmxAutoConfiguration
    регистрJMXуправляющий делами

    Интеграция JMX с Spring
    Spring регистрирует MBeans в JMX с помощью аннотаций аннотаций для отслеживания текущего состояния Java.

  • MultipartAutoConfiguration
    Регистрация процессоров передачи файлов
  • ServerPropertiesAutoConfiguration
    Он используется для инициализации связанных с контейнером свойств конфигурации, таких как адрес службы, порт и contextPath, а также для инициализации уникальных свойств каждого контейнера в соответствии с текущим типом контейнера, таких как maxThreads, uriEncoding и т. д. Tomcat. Соответствующий класс свойств:ServerProperties;
  • WebClientAutoConfiguration
    Зарегистрировать RestTemplate
  • WebMvcAutoConfiguration
    Зарегистрируйте связанные с SpringMvc процессоры, такие как ResourceResolver, RequestMappingHandlerAdapter, ExceptionHandlerExceptionResolver, ViewResolver, LocaleResolver и т. д.
  • WebSocketAutoConfiguration
    Зарегистрируйте процессоры, связанные с webSocket, и зарегистрируйте разные процессоры в соответствии с типом контейнера.

3. Если к зависимостям добавляются зависимости других функций, SpringBoot также реализует автоматическую адаптацию этих функций.Например, если мы добавим функцию JPA базы данных, это позволитJpaRepositoriesAutoConfigurationфункция автоматической настройки. Содержание базы данных будет представлено позже.

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


иллюстрировать
Для каждого класса конфигурации AutoConfiguration можно увидеть следующие аннотации.На основе этих аннотаций можно определить порядок инициализации этих AutoConfigurations:

  • @AutoConfigureOrder(-2147483648): чем меньше число, тем первым инициализируется
  • @AutoConfigureAfter({EmbeddedServletContainerAutoConfiguration.class}): загрузка после инициализации указанного класса конфигурации
  • @AutoConfigureBefore({WebMvcAutoConfiguration.class}): загружать до инициализации указанного класса конфигурации.

Возьмите на себя автоматическую настройку SpringBoot

мы представили@SpringBootApplicationЭта аннотация, поскольку она содержит@EnableAutoConfigurationа также@ComponentScanAnnotation может автоматически сканировать связанные классы автоконфигурации для реализации функции автоконфигурации.
Как было сказано выше, SpringBoot по умолчанию инициализирует множество автоматических конфигураций.Некоторые из этих конфигураций могут не использоваться в проекте.Как их удалить?

Удалите ненужные классы автоконфигурации

Например, нам не нужно включать автоматическую настройку webSocket и JMX, нам нужно@SpringBootApplicationуказано в этой аннотацииexcludeАтрибуты

@SpringBootApplication(exclude = {WebSocketAutoConfiguration.class,JmxAutoConfiguration.class})
public class SpringBootWebDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootWebDemoApplication.class, args);
    }
}

Явно укажите, какую автоконфигурацию необходимо включить

мы можем удалить@SpringBootApplicationАннотировать, использовать вместо@Конфигурация, @Импорт, @Сканирование компонентовобратите внимание, в@ImportЯвно укажите, какие автоконфигурации необходимо включить в аннотациях.

//@SpringBootApplication(exclude = {WebSocketAutoConfiguration.class,JmxAutoConfiguration.class})
@Configuration
@Import({
        DispatcherServletAutoConfiguration.class,
        EmbeddedServletContainerAutoConfiguration.class,
        ErrorMvcAutoConfiguration.class,
        HttpEncodingAutoConfiguration.class,
        HttpMessageConvertersAutoConfiguration.class,
        JacksonAutoConfiguration.class,
        MultipartAutoConfiguration.class,
        ServerPropertiesAutoConfiguration.class,
        WebMvcAutoConfiguration.class
})
@ComponentScan
public class SpringBootWebDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootWebDemoApplication.class, args);
    }
}


проиллюстрировать:

  • Здесь рекомендуется первый метод:@SpringBootApplication(exclude={});
  • На самом деле включение функции автоматической настройки по умолчанию повлияет только на время запуска проекта, поэтому нет особой необходимости отключать определенную функцию автоматической настройки;
  • В некоторых случаях, например, когда проекту требуется несколько источников данных, проект будет содержать несколько bean-компонентов DataSource, потому чтоDataSourceAutoConfigurationАвтоконфигурация может привязывать только один источник данных.В настоящее время, если в Spring зарегистрировано несколько компонентов DataSource, будет выдано исключение.

    1. В это время вы можете использовать для удаленияDataSourceAutoConfigurationПуть;
    2. Или вы можете объявить его в Bean-компоненте источника данных.@PrimaryАннотация, указав его как основной источник данных, затемDataSourceAutoConfigurationзагрузит только указанный@PrimaryОсновной источник данных аннотации, чтобы вы могли пользоваться преимуществами автоматической настройки SpringBoot.


Возьмите на себя автоматическую настройку WebMvc

Для веб-проекта важнее всего управление, связанное с Mvc, SpringBoot черезWebMvcAutoConfigurationЧтобы завершить автоматическую настройку, связанную с Mvc. Если вы хотите полностью взять на себя автоматическую настройку WebMvc, вы можете создать аннотацию в проекте@EnableWebMvcкласс конфигурации, например:

package com.example;
import org.apache.log4j.Logger;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.util.Properties;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example", useDefaultFilters = false, includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})
})
public class MvcConfig extends WebMvcConfigurationSupport {
    private static final Logger logger = Logger
            .getLogger(MvcConfig.class);
    /**
     * 描述 : <注册视图处理器>. <br>
     *<p>
     <使用方法说明>
     </p>
     * @return
     */
    @Bean
    public ViewResolver viewResolver() {
        logger.info("ViewResolver");
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/jsp/function/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
    /**
     * 描述 : <注册消息资源处理器>. <br>
     *<p>
     <使用方法说明>
     </p>
     * @return
     */
    @Bean
    public MessageSource messageSource() {
        logger.info("MessageSource");
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("config.messages.messages");
        return messageSource;
    }
    /**
     * 描述 : <注册servlet适配器>. <br>
     *<p>
     <只需要在自定义的servlet上用@Controller("映射路径")标注即可>
     </p>
     * @return
     */
    @Bean
    public HandlerAdapter servletHandlerAdapter(){
        logger.info("HandlerAdapter");
        return new SimpleServletHandlerAdapter();
    }
    /**
     * 描述 : <本地化拦截器>. <br>
     *<p>
     <使用方法说明>
     </p>
     * @return
     */
    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor(){
        logger.info("LocaleChangeInterceptor");
        return new LocaleChangeInterceptor();
    }
    /**
     * 描述 : <基于cookie的本地化资源处理器>. <br>
     *<p>
     <使用方法说明>
     </p>
     * @return
     */
    @Bean(name="localeResolver")
    public CookieLocaleResolver cookieLocaleResolver(){
        logger.info("CookieLocaleResolver");
        return new CookieLocaleResolver();
    }
    /**
     * 描述 : <添加拦截器>. <br>
     *<p>
     <使用方法说明>
     </p>
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // TODO Auto-generated method stub
        logger.info("addInterceptors start");
        registry.addInterceptor(localeChangeInterceptor());
        logger.info("addInterceptors end");
    }
    /**
     * 描述 : <资源访问处理器>. <br>
     *<p>
     <可以在jsp中使用/static/**的方式访问/WEB-INF/static/下的内容>
     </p>
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        logger.info("addResourceHandlers");
        registry.addResourceHandler("/static/**").addResourceLocations("/WEB-INF/static/");
    }
    /**
     * 描述 : <文件上传处理器>. <br>
     *<p>
     <使用方法说明>
     </p>
     * @return
     */
    @Bean(name="multipartResolver")
    public CommonsMultipartResolver commonsMultipartResolver(){
        logger.info("CommonsMultipartResolver");
        return new CommonsMultipartResolver();
    }
    /**
     * 描述 : <异常处理器>. <br>
     *<p>
     <系统运行时遇到指定的异常将会跳转到指定的页面>
     </p>
     * @return
     */
    @Bean(name="exceptionResolver")
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        logger.info("CP_SimpleMappingExceptionResolver");
        SimpleMappingExceptionResolver simpleMappingExceptionResolver= new SimpleMappingExceptionResolver();
        simpleMappingExceptionResolver.setDefaultErrorView("common_error");
        simpleMappingExceptionResolver.setExceptionAttribute("exception");
        Properties properties = new Properties();
        properties.setProperty("java.lang.RuntimeException", "common_error");
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        return simpleMappingExceptionResolver;
    }
}

На этом этапе, когда вы запустите проект в режиме отладки, вы увидитеWebMvcAutoConfigurationОн не настраивается автоматически, что указывает на то, что мы определяем его сами.MvcConfigполностью взял на себя автоматическую настройку по умолчанию, потому чтоWebMvcAutoConfigurationЕсть условная аннотация:

@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})

И в нашем случаеMvcConfigЭто класс реализации WebMvcConfigurationSupport, при добавлении@EnableWebMvcАннотация также импортирует класс реализации WebMvcConfigurationSupport: DelegatingWebMvcConfiguration.
,такMvcConfigНаследовать WebMvcConfigurationSupport не обязательно, но нам удобно кодировать.


Ссылаться на:Нулевая конфигурация SpringMVC4 — конфигурация веб-контекста [MvcConfig]


Если вы хотите продолжать использоватьWebMvcAutoConfigurationАвтоматическая конфигурация, но нужно только изменить или добавить некоторую конфигурацию в MVC, мы можем создать класс конфигурации и наследовать от абстрактного класса.WebMvcConfigurerAdapter, мы можем зарегистрировать собственный контроллер, реализуя методы абстрактного класса.

public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
    public WebMvcConfigurerAdapter() {
    }
    public void configurePathMatch(PathMatchConfigurer configurer) {
    }
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }
    public void addFormatters(FormatterRegistry registry) {
    }
    public void addInterceptors(InterceptorRegistry registry) {
    }
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }
    public void addCorsMappings(CorsRegistry registry) {
    }
    public void addViewControllers(ViewControllerRegistry registry) {
    }
    public void configureViewResolvers(ViewResolverRegistry registry) {
    }
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    }
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
    }
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    }
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    }
    public Validator getValidator() {
        return null;
    }
    public MessageCodesResolver getMessageCodesResolver() {
        return null;
    }
}

Например, мы можем добавить контроллер перехода вида следующим образом:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/demo/123").setViewName("/demo");
    }
}


Методы регистрации Servlet, Filter и Listener

1. Если это проект военного пакета, мы можем зарегистрировать Servlet, Filter и Listener дляWebApplicationInitializerв классе реализации

@Order(1)
public class CommonInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext)
            throws ServletException {
        //Log4jConfigListener
        servletContext.setInitParameter("log4jConfigLocation", "classpath:log4j.properties");
        servletContext.addListener(Log4jConfigListener.class);
        //OpenSessionInViewFilter
        OpenSessionInViewFilter hibernateSessionInViewFilter = new OpenSessionInViewFilter();
        FilterRegistration.Dynamic filterRegistration = servletContext.addFilter(
                "hibernateFilter", hibernateSessionInViewFilter);
        filterRegistration.addMappingForUrlPatterns(
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/");
        //DemoServlet
        DemoServlet demoServlet = new DemoServlet();
        ServletRegistration.Dynamic dynamic = servletContext.addServlet(
                "demoServlet", demoServlet);
        dynamic.setLoadOnStartup(2);
        dynamic.addMapping("/demo_servlet");
    }
}

2. Если это метод развертывания пакета jar, вы можете зарегистрировать его для любого@Configurationв классе конфигурации

@Configuration
public class WebConfig {
    @Bean
    public ServletRegistrationBean servletRegistrationBean_demo1(){
        return new ServletRegistrationBean(new DemoServlet(),"/demo-servlet1");
    }
    @Bean
    public ServletRegistrationBean servletRegistrationBean_demo2(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.addUrlMappings("/demo-servlet2");
        servletRegistrationBean.setServlet(new DemoServlet2());
        return servletRegistrationBean;
    }
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new OpenSessionInViewFilter());
        Set<String> set = new HashSet<String>();
        set.add("/");
        filterRegistrationBean.setUrlPatterns(set);
        return filterRegistrationBean;
    }
    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean(){
        ServletListenerRegistrationBean servletListenerRegistrationBean =  new ServletListenerRegistrationBean();
        servletListenerRegistrationBean.setListener(new Log4jConfigListener());
        servletListenerRegistrationBean.addInitParameter("log4jConfigLocation","classpath:log4j.properties");
        return servletListenerRegistrationBean;
    }
}


Суммировать

Опишите автоматическую настройку SpringBoot одним предложением:Это набор классов конфигурации Spring, которые реализуют регистрацию Bean-компонентов на основе условных аннотаций.