一、spring注解之如何导入Bean的几种方式

1)@Bean注解
2) 包扫描来加载Bean 比如标识@Controller @Service @Repository @Compent
3) @Import几种取值来注册bean
①:实现ImportSelector接口的类
写一个配置类在配置类上标注一个@Import的注解,在@Import注解的value值 写自己需要导入的组件

  1. @Configuration
  2. @Import(value = {TestSelector.class})
  3. public class TestgConfig {
  4. }
  5. public class TestSelector implements ImportSelector {
  6. @Override
  7. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  8. return new String[]{"com.zhao.service.TestServiceImpl"};
  9. }
  10. }

②:实现ImportBeanDefinitionRegistrar接口來注冊bean

  1. public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  2. @Override
  3. public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
  4. //定义一个BeanDefinition
  5. RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDao.class);
  6. //把自定义的bean定义导入到容器中
  7. beanDefinitionRegistry.registerBeanDefinition("testDao",rootBeanDefinition);
  8. }
  9. }

4)实现factoryBean的方式来导入组件

二、spring底层条件装配的原理@Conditional

通过实现Condition接口,定义匹配方法,来达到条件加载

  1. public class TestConditional implements Condition {
  2. @Override
  3. public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
  4. //容器中包含testAspect组件才返回Ture
  5. if(conditionContext.getBeanFactory().containsBean("testAspect")){
  6. return true;
  7. }else{
  8. return false;
  9. }
  10. }
  11. }
  12. @Bean
  13. public TestAspect testAspect() {
  14. System.out.println("testAspect组件自动装配到容器中");
  15. return new TestAspect();
  16. }
  17. @Bean
  18. @Conditional(value = TestConditional.class)
  19. public TestLog testLog() {
  20. System.out.println("testgLog组件自动装配到容器中");
  21. return new TestLog();
  22. }

三、springboot自动装配原理

1、Springboot注解组合图

image.png

先分析AutoConfigurationImportSelector做了什么事情

  1. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  2. if (!isEnabled(annotationMetadata)) {
  3. return NO_IMPORTS;
  4. }
  5. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  6. .loadMetadata(this.beanClassLoader);
  7. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  8. //获取候选的配置类
  9. List<String> configurations = getCandidateConfigurations(annotationMetadata,
  10. attributes);
  11. //移除重复的
  12. configurations = removeDuplicates(configurations);
  13. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  14. checkExcludedClasses(configurations, exclusions);
  15. configurations.removeAll(exclusions);
  16. configurations = filter(configurations, autoConfigurationMetadata);
  17. fireAutoConfigurationImportEvents(configurations, exclusions);
  18. //返回出去
  19. return StringUtils.toStringArray(configurations);
  20. }
  21. //获取候选的配置类
  22. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
  23. AnnotationAttributes attributes) {
  24. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
  25. getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
  26. Assert.notEmpty(configurations,
  27. "No auto configuration classes found in META-INF/spring.factories. If you "
  28. + "are using a custom packaging, make sure that file is correct.");
  29. return configurations;
  30. }
  31. //加载配置类
  32. public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
  33. String factoryClassName = factoryClass.getName();
  34. return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
  35. }
  36. private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  37. MultiValueMap<String, String> result = cache.get(classLoader);
  38. if (result != null) {
  39. return result;
  40. }
  41. try {
  42. //"META-INF/spring.factories" 去类路径下该文件中加载 EnableAutoConfiguration.class
  43. Enumeration<URL> urls = (classLoader != null ?
  44. classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
  45. ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
  46. result = new LinkedMultiValueMap<>();
  47. //遍历解析出来的集合
  48. while (urls.hasMoreElements()) {
  49. URL url = urls.nextElement();
  50. UrlResource resource = new UrlResource(url);
  51. //放在Properties中
  52. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  53. for (Map.Entry<?, ?> entry : properties.entrySet()) {
  54. String factoryClassName = ((String) entry.getKey()).trim();
  55. for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
  56. result.add(factoryClassName, factoryName.trim());
  57. }
  58. }
  59. }
  60. cache.put(classLoader, result);
  61. //返回
  62. return result;
  63. }
  64. catch (IOException ex) {
  65. throw new IllegalArgumentException("Unable to load factories from location [" +
  66. FACTORIES_RESOURCE_LOCATION + "]", ex);
  67. }
  68. }

主要是扫描spring-boot-autoconfigure\2.1.5.RELEASE\spring-boot-autoconfigure-
2.0.8.RELEASE.jar!\META-INF\spring.factories 中EnableAutoConfiguration对应的全类名,这里的都是自动配置类

分析源码1: org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration

  1. @Configuration //标识是一个自动配置类
  2. @EnableConfigurationProperties(HttpEncodingProperties.class) //启动指定类的配置功能,并且把配置文件中的属性和HttpEncodingProperties类的属性进行绑定
  3. @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) //spring底层的@Conditional注解的变种 就是用来进行条件判断的,判断是否为web环境
  4. @ConditionalOnClass(CharacterEncodingFilter.class)//判断环境中是否没有这个类
  5. //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
  6. //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的
  7. @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
  8. public class HttpEncodingAutoConfiguration {
  9. //自动配置类的属性映射
  10. private final HttpEncodingProperties properties;
  11. public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
  12. this.properties = properties;
  13. }
  14. //配置一个 CharacterEncodingFilter 是springmvc解决乱码的 ,若容器中没有该组件 ,那么就会创建该组件
  15. @Bean
  16. @ConditionalOnMissingBean
  17. public CharacterEncodingFilter characterEncodingFilter() {
  18. CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
  19. filter.setEncoding(this.properties.getCharset().name());
  20. filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
  21. filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
  22. return filter;
  23. }
  24. @Bean
  25. public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
  26. return new LocaleCharsetMappingsCustomizer(this.properties);
  27. }
  28. private static class LocaleCharsetMappingsCustomizer implements
  29. WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
  30. private final HttpEncodingProperties properties;
  31. LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {
  32. this.properties = properties;
  33. }
  34. @Override
  35. public void customize(ConfigurableServletWebServerFactory factory) {
  36. if (this.properties.getMapping() != null) {
  37. factory.setLocaleCharsetMappings(this.properties.getMapping());
  38. }
  39. }
  40. @Override
  41. public int getOrder() {
  42. return 0;
  43. }
  44. }
  45. }

四、spring Boot的jar包的启动流程

image.png

EmbeddedWebServerFactoryCustomizerAutoConfiguration(内嵌web容器工厂自定义定制器装配类)

  1. @Configuration
  2. @ConditionalOnWebApplication
  3. @EnableConfigurationProperties(ServerProperties.class)
  4. public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
  5. //配置tomcat的
  6. @Configuration
  7. @ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
  8. public static class TomcatWebServerFactoryCustomizerConfiguration {
  9. @Bean
  10. public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
  11. Environment environment, ServerProperties serverProperties) {
  12. return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
  13. }
  14. }
  15. //配置jetty
  16. @Configuration
  17. @ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
  18. public static class JettyWebServerFactoryCustomizerConfiguration {
  19. @Bean
  20. public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(
  21. Environment environment, ServerProperties serverProperties) {
  22. return new JettyWebServerFactoryCustomizer(environment, serverProperties);
  23. }
  24. }
  25. //配置undertow的
  26. @Configuration
  27. @ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
  28. public static class UndertowWebServerFactoryCustomizerConfiguration {
  29. @Bean
  30. public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
  31. Environment environment, ServerProperties serverProperties) {
  32. return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
  33. }
  34. }
  35. }

tomat 工厂定制器 是用来修改设置容器的内容的(把serverProperties的属性设置到tomcat的创建工厂中)

  1. public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
  2. //..........................其他代码省略。。。。。。。。。。。。。。
  3. @Override
  4. public void customize(ConfigurableTomcatWebServerFactory factory) {
  5. ServerProperties properties = this.serverProperties;
  6. ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
  7. PropertyMapper propertyMapper = PropertyMapper.get();
  8. propertyMapper.from(tomcatProperties::getBasedir).whenNonNull()
  9. .to(factory::setBaseDirectory);
  10. propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull()
  11. .as(Duration::getSeconds).as(Long::intValue)
  12. .to(factory::setBackgroundProcessorDelay);
  13. customizeRemoteIpValve(factory);
  14. propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive)
  15. .to((maxThreads) -> customizeMaxThreads(factory,
  16. tomcatProperties.getMaxThreads()));
  17. propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive)
  18. .to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
  19. propertyMapper.from(() -> determineMaxHttpHeaderSize()).when(this::isPositive)
  20. .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
  21. maxHttpHeaderSize));
  22. propertyMapper.from(tomcatProperties::getMaxHttpPostSize)
  23. .when((maxHttpPostSize) -> maxHttpPostSize != 0)
  24. .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory,
  25. maxHttpPostSize));
  26. propertyMapper.from(tomcatProperties::getAccesslog)
  27. .when(ServerProperties.Tomcat.Accesslog::isEnabled)
  28. .to((enabled) -> customizeAccessLog(factory));
  29. propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull()
  30. .to(factory::setUriEncoding);
  31. propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
  32. .to((connectionTimeout) -> customizeConnectionTimeout(factory,
  33. connectionTimeout));
  34. propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
  35. .to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
  36. propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
  37. .to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
  38. customizeStaticResources(factory);
  39. customizeErrorReportValve(properties.getError(), factory);
  40. }
  41. }

ServletWebServerFactoryAutoConfiguration Servletweb工厂自动配置类

  1. @Configuration
  2. @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
  3. @ConditionalOnClass(ServletRequest.class)
  4. @ConditionalOnWebApplication(type = Type.SERVLET)
  5. @EnableConfigurationProperties(ServerProperties.class)
  6. @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
  7. ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
  8. ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
  9. ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
  10. public class ServletWebServerFactoryAutoConfiguration {
  11. @Bean
  12. public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
  13. ServerProperties serverProperties) {
  14. return new ServletWebServerFactoryCustomizer(serverProperties);
  15. }
  16. @Bean
  17. @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
  18. public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
  19. ServerProperties serverProperties) {
  20. return new TomcatServletWebServerFactoryCustomizer(serverProperties);
  21. }
  22. }
  23. //.....................................................ServletWebServerFactoryCustomizer核心代码...........................................
  24. public void customize(ConfigurableServletWebServerFactory factory) {
  25. PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
  26. map.from(this.serverProperties::getPort).to(factory::setPort);
  27. map.from(this.serverProperties::getAddress).to(factory::setAddress);
  28. map.from(this.serverProperties.getServlet()::getContextPath)
  29. .to(factory::setContextPath);
  30. map.from(this.serverProperties.getServlet()::getApplicationDisplayName)
  31. .to(factory::setDisplayName);
  32. map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
  33. map.from(this.serverProperties::getSsl).to(factory::setSsl);
  34. map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
  35. map.from(this.serverProperties::getCompression).to(factory::setCompression);
  36. map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
  37. map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
  38. map.from(this.serverProperties.getServlet()::getContextParameters)
  39. .to(factory::setInitParameters);
  40. }
  41. //---------------------------------------------TomcatServletWebServerFactoryCustomizer核心定制代码-----------------------------------
  42. public void customize(TomcatServletWebServerFactory factory) {
  43. ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat();
  44. if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) {
  45. factory.getTldSkipPatterns()
  46. .addAll(tomcatProperties.getAdditionalTldSkipPatterns());
  47. }
  48. if (tomcatProperties.getRedirectContextRoot() != null) {
  49. customizeRedirectContextRoot(factory,
  50. tomcatProperties.getRedirectContextRoot());
  51. }
  52. if (tomcatProperties.getUseRelativeRedirects() != null) {
  53. customizeUseRelativeRedirects(factory,
  54. tomcatProperties.getUseRelativeRedirects());
  55. }
  56. }

ServletWebServerFactoryConfiguration 容器工厂配置类

  1. @Configuration
  2. class ServletWebServerFactoryConfiguration {
  3. @Configuration
  4. @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
  5. @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
  6. public static class EmbeddedTomcat {
  7. //配置tomcat 容器工厂
  8. @Bean
  9. public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
  10. return new TomcatServletWebServerFactory();
  11. }
  12. }

启动的主流程
org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String…)
1、传入主配置类,以及命令行参数
2、创建SpringApplication对象

  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. //保存主配置类
  5. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  6. //保存web应用的类型
  7. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  8. //保存 容器初始化器(ApplicationContextInitializer类型的)
  9. setInitializers((Collection) getSpringFactoriesInstances(
  10. ApplicationContextInitializer.class));
  11. //把监听器保存到 SpringApplication中[ApplicationListener]
  12. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  13. //保存主配置类
  14. this.mainApplicationClass = deduceMainApplicationClass();
  15. }
  16. //还是去META-INFO/spring.factories 中获取ApplicationContextInitializer 类型,用于初始化容器
  17. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
  18. Class<?>[] parameterTypes, Object... args) {
  19. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  20. // Use names and ensure unique to protect against duplicates
  21. Set<String> names = new LinkedHashSet<>(
  22. SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  23. List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
  24. classLoader, args, names);
  25. AnnotationAwareOrderComparator.sort(instances);
  26. return instances;
  27. }
  28. //查找主配置类 查询的依据就是看哪个方法是否有main方法
  29. private Class<?> deduceMainApplicationClass() {
  30. try {
  31. StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
  32. for (StackTraceElement stackTraceElement : stackTrace) {
  33. if ("main".equals(stackTraceElement.getMethodName())) {
  34. return Class.forName(stackTraceElement.getClassName());
  35. }
  36. }
  37. }
  38. catch (ClassNotFoundException ex) {
  39. // Swallow and continue
  40. }
  41. return null;
  42. }

3、运行SpringbootApplication的run方法行

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. //创建一个 容器对象
  5. ConfigurableApplicationContext context = null;
  6. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  7. configureHeadlessProperty();
  8. //去meta-info/spring.factories中获取SpringApplicationRunListener 监听器(事件发布监听器)
  9. SpringApplicationRunListeners listeners = getRunListeners(args);
  10. //发布容器 starting事件(通过spring的事件多播器)
  11. listeners.starting();
  12. try {
  13. //封装命令行参数
  14. ApplicationArguments applicationArguments = new DefaultApplicationArguments(
  15. args);
  16. //准备容器环境
  17. //1:获取或者创建环境
  18. //2:把命令行参数设置到环境中
  19. //3:通过监听器发布环境准备事件
  20. ConfigurableEnvironment environment = prepareEnvironment(listeners,
  21. applicationArguments);
  22. configureIgnoreBeanInfo(environment);
  23. //打印springboot的图标
  24. Banner printedBanner = printBanner(environment);
  25. //创建容器 根据webApplicationType 来创建容器 通过反射创建
  26. context = createApplicationContext();
  27. //去meta-info类中 获取异常报告
  28. exceptionReporters = getSpringFactoriesInstances(
  29. SpringBootExceptionReporter.class,
  30. new Class[] { ConfigurableApplicationContext.class }, context);
  31. //准备环境
  32. //1:把环境设置到容器中
  33. //2: 循环调用AppplicationInitnazlier 进行容器初始化工作
  34. //3:发布容器上下文准备完成事件
  35. //4:注册关于springboot特性的相关单例Bean
  36. //5:发布容器上下文加载完毕事件
  37. prepareContext(context, environment, listeners, applicationArguments,printedBanner);
  38. refreshContext(context);
  39. //运行 ApplicationRunner 和CommandLineRunner
  40. afterRefresh(context, applicationArguments);
  41. stopWatch.stop();
  42. if (this.logStartupInfo) {
  43. new StartupInfoLogger(this.mainApplicationClass)
  44. .logStarted(getApplicationLog(), stopWatch);
  45. }
  46. //发布容器启动事件
  47. listeners.started(context);
  48. //运行 ApplicationRunner 和CommandLineRunner
  49. callRunners(context, applicationArguments);
  50. }
  51. catch (Throwable ex) {
  52. //出现异常;调用异常分析保护类进行分析
  53. handleRunFailure(context, ex, exceptionReporters, listeners);
  54. throw new IllegalStateException(ex);
  55. }
  56. try {
  57. //发布容器运行事件
  58. listeners.running(context);
  59. }
  60. catch (Throwable ex) {
  61. handleRunFailure(context, ex, exceptionReporters, null);
  62. throw new IllegalStateException(ex);
  63. }
  64. return context;
  65. }

4、org.springframework.boot.SpringApplication#refreshContext
5、org.springframework.context.support.AbstractApplicationContext#refresh
6、org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
7、org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
7.1)org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#getWebServer
7.2)org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor#postProces
7.3)org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor#postProcessBeforeInitialization
我们往容器中导入了 BeanPostProcessorsRegistrar 他实现了 ImportBeanDefinitionRegistrar 在他的 registerBeanDefinitions注册Bean定义的时候 注册了 webServerFactoryCustomizerBeanPostProcessor

  1. public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
  2. private ConfigurableListableBeanFactory beanFactory;
  3. @Override
  4. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  5. if (beanFactory instanceof ConfigurableListableBeanFactory) {
  6. this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
  7. }
  8. }
  9. @Override
  10. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
  11. BeanDefinitionRegistry registry) {
  12. if (this.beanFactory == null) {
  13. return;
  14. }
  15. registerSyntheticBeanIfMissing(registry,
  16. "webServerFactoryCustomizerBeanPostProcessor",
  17. WebServerFactoryCustomizerBeanPostProcessor.class);
  18. registerSyntheticBeanIfMissing(registry,
  19. "errorPageRegistrarBeanPostProcessor",
  20. ErrorPageRegistrarBeanPostProcessor.class);
  21. }
  22. }

8、org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
创建tomcat 并且容器启动

  1. public WebServer getWebServer(ServletContextInitializer... initializers) {
  2. Tomcat tomcat = new Tomcat();
  3. File baseDir = (this.baseDirectory != null) ? this.baseDirectory
  4. : createTempDir("tomcat");
  5. tomcat.setBaseDir(baseDir.getAbsolutePath());
  6. Connector connector = new Connector(this.protocol);
  7. tomcat.getService().addConnector(connector);
  8. customizeConnector(connector);
  9. tomcat.setConnector(connector);
  10. tomcat.getHost().setAutoDeploy(false);
  11. configureEngine(tomcat.getEngine());
  12. for (Connector additionalConnector : this.additionalTomcatConnectors) {
  13. tomcat.getService().addConnector(additionalConnector);
  14. }
  15. prepareContext(tomcat.getHost(), initializers);
  16. return getTomcatWebServer(tomcat);
  17. }
  18. protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
  19. //端口大于0启动启动
  20. return new TomcatWebServer(tomcat, getPort() >= 0);
  21. }
  22. public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
  23. Assert.notNull(tomcat, "Tomcat Server must not be null");
  24. this.tomcat = tomcat;
  25. this.autoStart = autoStart;
  26. initialize();
  27. }
  28. //tomcat启动流程
  29. private void initialize() throws WebServerException {
  30. TomcatWebServer.logger
  31. .info("Tomcat initialized with port(s): " + getPortsDescription(false));
  32. synchronized (this.monitor) {
  33. try {
  34. addInstanceIdToEngineName();
  35. Context context = findContext();
  36. context.addLifecycleListener((event) -> {
  37. if (context.equals(event.getSource())
  38. && Lifecycle.START_EVENT.equals(event.getType())) {
  39. // Remove service connectors so that protocol binding doesn't
  40. // happen when the service is started.
  41. removeServiceConnectors();
  42. }
  43. });
  44. // Start the server to trigger initialization listeners
  45. this.tomcat.start();
  46. // We can re-throw failure exception directly in the main thread
  47. rethrowDeferredStartupExceptions();
  48. try {
  49. ContextBindings.bindClassLoader(context, context.getNamingToken(),
  50. getClass().getClassLoader());
  51. }
  52. catch (NamingException ex) {
  53. // Naming is not enabled. Continue
  54. }
  55. // Unlike Jetty, all Tomcat threads are daemon threads. We create a
  56. // blocking non-daemon to stop immediate shutdown
  57. startDaemonAwaitThread();
  58. }
  59. catch (Exception ex) {
  60. stopSilently();
  61. throw new WebServerException("Unable to start embedded Tomcat", ex);
  62. }
  63. }
  64. }

9、 在IOC 容器中的
org.springframework.context.support.AbstractApplicationContext#refresh 的
onReFresh()带动tomcat启动
然后在接着执行 ioc容器的其他步骤。