转载

Spring Boot启动源码分析

@EnableAutoConfiguration 注解的秘密

本文由javacoder.cn整理,谢绝转载

@EnableAutoConfiguration本身的定义

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage{}
 
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

@Import的两个类的作用如下

AutoConfigurationPackages.Registrar 的作用是添加对@AutoConfigurationPackage注解作用的类所在包名的扫描,并将该包名下扫描到的需要注册的bean注册

EnableAutoConfigurationImportSelector对SpringFactoriesLoader 从"META-INF/spring.factories"中"key=org.springframework.boot.autoconfigure.EnableAutoConfiguration"加载的那一堆使用@Configuration注解的配置类的解析注册

spring-boot-autoconfigure-xxx.jar下的"META-INF/spring.factories"文件中定义了spring的工厂扩展机制。@EnableAutoConfiguration注解处理"key=org.springframework.boot.autoconfigure.EnableAutoConfiguration"对应的值(以逗号分隔,@Configuration注解的配置类),其中的org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration用于初始化嵌入式ServletContainer。

具体的实现参考如下方法

org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector.selectImports()

org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass()解析入口配置类,也就是我们通过SpringApplication.run(Application.class, args);方法传入的使用@Configuration注解的类

org.springframework.context.annotation.ConfigurationClassPostProcessor对@EnableAutoConfiguration注解的处理

EmbeddedServletContainer初始化

servlet 3.0 specification指定了编程式初始化servlet container的接口

javax.servlet.ServletContainerInitializer.onStartup(Set<Class<?>> c, ServletContext ctx) ;

而spring 将初始化ServletContainer的工作代理给WebApplicationInitializer接口,具体参考SpringServletContainerInitializer类的实现及注释

一个基于代码配置sevletContainer的示例如下,摘录自WebApplicationInitializer 的javadoc

public class MyWebAppInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext container) {
      // Create the 'root' Spring application context
      AnnotationConfigWebApplicationContext rootContext =
        new AnnotationConfigWebApplicationContext();
      rootContext.register(AppConfig.class);
 
      // Manage the lifecycle of the root application context
      container.addListener(new ContextLoaderListener(rootContext));
 
      // Create the dispatcher servlet's Spring application context
      AnnotationConfigWebApplicationContext dispatcherContext =
        new AnnotationConfigWebApplicationContext();
      dispatcherContext.register(DispatcherConfig.class);
 
      // Register and map the dispatcher servlet
      ServletRegistration.Dynamic dispatcher =
        container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
      dispatcher.setLoadOnStartup(1);
      dispatcher.addMapping("/");
    }
 }

但是spring boot使用的是org.springframework.boot.context.embedded.ServletContextInitializer接口而不是WebApplicationInitializer,目的是为了不被ServletContainer自动初始化,具体的实现类为FilterRegistrationBean, ServletRegistrationBean,分别完成Filter和Servlet的注册

Spring MVC 请求映射的初始化

RequestMappingHandlerMapping.afterPropertiesSet()

完整的序列图如下

Spring Boot启动源码分析

Posted in:MySQL practise

原文  http://www.javacoder.cn/?p=1253
正文到此结束
Loading...