美文网首页
SpringBoot自动装配

SpringBoot自动装配

作者: 枫叶红花 | 来源:发表于2023-01-04 18:22 被阅读0次

    1.SpringBoot自动装配原理

    1.1 核心是这个@SpringBootApplication注解
    里面主要包含三个注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan;
    1.2 @EnableAutoConfiguration:表示开启自动装配;@ComponentScan:表示扫描当前配置类所在路径的全部配置类。
    1.3其中@EnableAutoConfiguration这个注解里面引入了一个@Import(AutoConfigurationImportSelector.class),而这个类实现了DeferredImportSelector接口。这个接口的selectImports()将在spring解析完我们自定义的配置类之后,才会解析自动配置类。
    1)在selectImports()方法中的getAutoConfigurationEntry()将会从spring.factories文件读取key=org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的自动配置类:


    spring.factories

    2)在getAutoConfigurationEntry()中,getConfigurationClassFilter()方法会读取spring.factories 文件中key=AutoConfigurationImportFilter的值,同时会得到三个条件过滤器,OnBeanCondition、OnClassCondition、OnWebApplicationCondition使用这三个注解进一步过滤掉不符合的自动配置类:


    spring.factories
    3)在过滤器比较筛选自动配置类时,会读取"META-INF/spring-autoconfigure-metadata.properties"文件中的内容,进行加快筛选:
    spring-autoconfigure-metadata.properties

    2.AutoConfigurationImportSelector的源码解析

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 会在所有@Configuration都解析完了之后才执行
    
        if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    
    // 获取自动配置类(spring.factories中所导入的)
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
    
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return EMPTY_ENTRY;
            }
            // 获取@EnableAutoConfiguration的属性 比如exclude excludeName
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            // 获取spring.factories中@EnableAutoConfiguration对应的所有的AutoConfiguration(自动配置类)
            List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
            // 去重(也就是按类名去重)
            configurations = removeDuplicates(configurations);
            // 获取需要排除的AutoConfiguration,可以通过@EnableAutoConfiguration注解的exclude属性,或者spring.autoconfigure.exclude来配置
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    
            // 排除部分自动装配类
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
    
            // 获取spring.factories中的AutoConfigurationImportFilter对AutoConfiguration进行过滤
            // 默认会拿到OnBeanCondition、OnClassCondition、OnWebApplicationCondition
            // 这三个会去判断上面的AutoConfiguration是否符合它们自身所要求的条件,不符合的会过滤掉,表示不会进行解析了
            // 会利用spring-autoconfigure-metadata.properties中的配置来进行过滤
            configurations = getConfigurationClassFilter().filter(configurations);
            // configurations表示合格的,exclusions表示被排除的,把它们记录在条件报告中
            fireAutoConfigurationImportEvents(configurations, exclusions);
    
            // 最后返回的都是符合条件的自动装配类
            return new AutoConfigurationEntry(configurations, exclusions);
        }
    
    private ConfigurationClassFilter getConfigurationClassFilter() {
        if (this.configurationClassFilter == null) {
            // 读取spring.factories中key = AutoConfigurationImportFilter的value
            List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
            for (AutoConfigurationImportFilter filter : filters) {
                invokeAwareMethods(filter);
            }
            // 给filter集合赋值
            this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
        }
        return this.configurationClassFilter;
    }
    

    ConfigurationClassFilter#filter():

    List<String> filter(List<String> configurations) {
        long startTime = System.nanoTime();
        // configurations就是读取到的自动配置类
        String[] candidates = StringUtils.toStringArray(configurations);
        boolean skipped = false;
    
        // 逐个利用AutoConfigurationImportFilter来判断所有的自动配置类的条件是否匹配,匹配结果存在match数组中
        // 这里过滤器的顺序是spring.factories文件中配置的顺序
        for (AutoConfigurationImportFilter filter : this.filters) {
            // 调用具体过滤器实现的match方法
            boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
    
            for (int i = 0; i < match.length; i++) {
                if (!match[i]) {
                    candidates[i] = null;
                    skipped = true;
                }
            }
        }
    
        // 全部都匹配
        if (!skipped) {
            return configurations;
        }
    
        // 把匹配的记录在result集合中,最后返回
        List<String> result = new ArrayList<>(candidates.length);
        for (String candidate : candidates) {
            if (candidate != null) {
                result.add(candidate);
            }
        }
        if (logger.isTraceEnabled()) {
            int numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                    + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
        }
        return result;
    }
    

    这里的过滤器只有三个并不是全的,来源就是spring.factories中定义的:


    三种过滤器

    3.@AutoConfigurationPackage自动配置包路径

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {}
    

    主要执行的方法是registerBeanDefinitions():

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
       @Override
       public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
          // 将MyApplication.class所在的包路径注册成BeanDefinition,
          // 方便第三方减少配置,比如mybatis不用配置扫描路径,直接获取这个BeanDefinition
          register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
       }
    }
    
    PackageImports(AnnotationMetadata metadata) {
        // 获取注解的属性
        AnnotationAttributes attributes = AnnotationAttributes
                .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
        // 注解属性的value
        List<String> packageNames = new ArrayList<>(Arrays.asList(attributes.getStringArray("basePackages")));
        for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
            packageNames.add(basePackageClass.getPackage().getName());
        }
        // 当前配置类所在的包路径
        if (packageNames.isEmpty()) {
            // metadata.getClassName() :获取当前配置类的类名
            // ClassUtils.getPackageName:获取配置类所在的包的路径
            packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));
        }
        this.packageNames = Collections.unmodifiableList(packageNames);
    }
    

    该方法register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])),最终会将收到的包路径注册到Spring容器当中,方便第三方对接时不用填写扫描路径也仍然可以获取到扫描路径。

    4.@ComponentScan中的两个excluseFilter

    1.TypeExcludeFilter.class

    public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {
    
        private BeanFactory beanFactory;
        // 所有这个TypeExcludeFilter类型的Bean集合
        private Collection<TypeExcludeFilter> delegates;
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            this.beanFactory = beanFactory;
        }
    
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
        throws IOException {
            if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
    
                // 从Spring容器中获取TypeExcludeFilter,然后进行匹配,匹配的则不解析
                for (TypeExcludeFilter delegate : getDelegates()) {
                    // 调用自定义的TypeExcludeFilter的match方法,匹配就排除这个类
                    if (delegate.match(metadataReader, metadataReaderFactory)) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        private Collection<TypeExcludeFilter> getDelegates() {
            Collection<TypeExcludeFilter> delegates = this.delegates;
            if (delegates == null) {
                // 从Spring容器获取这个类型的Bean
                delegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
                this.delegates = delegates;
            }
            return delegates;
        }
    
    }
    

    2.AutoConfigurationExcludeFilter.class

    public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {
    
        private ClassLoader beanClassLoader;
    
        private volatile List<String> autoConfigurations;
    
        @Override
        public void setBeanClassLoader(ClassLoader beanClassLoader) {
            this.beanClassLoader = beanClassLoader;
        }
    
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
        throws IOException {
            // 这个方法就是验证当前类是否是配置类并且是自动配置类
            // 如果符合,就排除这个类,不去解析,让@EnableAutoConfiguration那边去处理
            return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
        }
    
        // 当前类是否有@Configuration注解
        private boolean isConfiguration(MetadataReader metadataReader) {
            return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
        }
    
        // 当前类是否是自动配置类
        private boolean isAutoConfiguration(MetadataReader metadataReader) {
            return getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
        }
    
        protected List<String> getAutoConfigurations() {
            if (this.autoConfigurations == null) {
                this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
                                                                                 this.beanClassLoader);
            }
            return this.autoConfigurations;
        }
    
    }
    

    这两个过滤器都是在扫描阶段过滤掉部分类,而AutoConfigurationExcludeFilter则是过滤自动配置类;TypeExcludeFilter根据match方法匹配,符合就过滤掉。
    1.为什么要在扫描阶段过滤自动配置类呢?
    因为@EnableAutoConfiguration实现了DeferredImportSelector接口,而这个接口会在所有配置类解析完之后,才会调用的,在扫描阶段过滤自动配置类可以提高性能,也保证了配置类的解析顺序。

    2.我们在继承TypeExcludeFilter重写match方法时,如果是用@Bean注入Spring容器中,将不会生效。
    和执行顺序有关,@Component、@ComponentScan会先执行,@Bean在后面执行。当扫描解析配置类时,@Bean对应的Bean对象还没生成添加到Spring容器中。

    对于这个问题的解决办法,可以在扫描前,就将我们重写的TypeExcludeFilter添加到容器中。
    1)比如可以实现ApplicationContextInitializer初始化器,然后再spring.factories中配置我们实现的类;
    2)然后再initialize方法中将我们的实现类注册到spring容器当中。

    5.Starter机制

    Springboot中的Starter机制,就是一个Maven依赖,当我们在项目中引入spring-boot-starter-web依赖时,实际上引入了spring-boot-starter、spring-boot-starter-json、spring-boot-starter-tomcat等和Web开发相关的依赖包。
    然后再通过条件注解用来判断当前应用的依赖中是否存在某个类或某些类,这样就可以动态的注入某些类。

    对于@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) 这个注解,如果Servlet.class类不存在,但是运行时不报错,SpringBoot是怎么处理的?
    1.我们引入某个依赖时,依赖中的文件都是已经编译好的,因此在我们项目编译期间,是不会再次编译的。
    2.运行时不报错,是因为Springboot使用了ASM技术,直接处理字节码文件,而不是使用反射生成实例,通过获取某个类的类名,再使用类加载器去验证是否存在。

    6.自动装配Tomcat

    1.创建WebServer

    ServletWebServerApplicationContext#onRefresh():

    protected void onRefresh() {
        super.onRefresh();
        try {
            // 启动Tomcat
            createWebServer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
        }
    }
    
    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        if (webServer == null && servletContext == null) {
            // 获取具体的WebServerFactory,比如TomcatServletWebServerFactory
            ServletWebServerFactory factory = getWebServerFactory();
            this.webServer = factory.getWebServer(getSelfInitializer()); // 这个方法启动tomcat
    
            getBeanFactory().registerSingleton("webServerGracefulShutdown",
                    new WebServerGracefulShutdownLifecycle(this.webServer));
            getBeanFactory().registerSingleton("webServerStartStop",
                    new WebServerStartStopLifecycle(this, this.webServer));
        }
        else if (servletContext != null) {
            try {
                getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context", ex);
            }
        }
        initPropertySources();
    }
    

    getWebServerFactory()获取ServletWebServerFactory实例:

    protected ServletWebServerFactory getWebServerFactory() {
        // Use bean names so that we don't consider the hierarchy
        //通过类型获取beanName
        String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); 
        // 期间发现多个或没有都会报错
        if (beanNames.length == 0) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
                                                  + "ServletWebServerFactory bean.");
        }
        if (beanNames.length > 1) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
                                                  + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
        }
        // 这里才会返回对应的Bean实例
        return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    }
    

    2.ServletWebServerFactoryAutoConfiguration自动配置类:

    这个类Import了EmbeddedTomcat.class,EmbeddedJetty.class,EmbeddedUndertow.class 三个类,就是为了生成对应的WebServer实例。

    @Configuration(proxyBeanMethods = false)
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @ConditionalOnClass(ServletRequest.class)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @EnableConfigurationProperties(ServerProperties.class) //ServerProperties用于读取properties配置文件,里面以server开头的内容
    @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
            ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
            ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
            ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
    public class ServletWebServerFactoryAutoConfiguration {
    
        @Bean
        public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
                ObjectProvider<WebListenerRegistrar> webListenerRegistrars,
                ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers) {
            return new ServletWebServerFactoryCustomizer(serverProperties,
                    webListenerRegistrars.orderedStream().collect(Collectors.toList()),
                    cookieSameSiteSuppliers.orderedStream().collect(Collectors.toList()));
        }
    
        @Bean
        @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
        public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
                ServerProperties serverProperties) {
            return new TomcatServletWebServerFactoryCustomizer(serverProperties);
        }
    
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
        @ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
        static class ForwardedHeaderFilterConfiguration {
    
            @Bean
            @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
            ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
                return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
            }
    
            @Bean
            FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(
                    ObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {
                ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
                customizerProvider.ifAvailable((customizer) -> customizer.customize(filter));
                FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
                registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
                registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
                return registration;
            }
    
        }
    
        interface ForwardedHeaderFilterCustomizer {
    
            void customize(ForwardedHeaderFilter filter);
    
        }
    
        /**
         * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
         * {@link ImportBeanDefinitionRegistrar} for early registration.
         */
        public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
    
            private ConfigurableListableBeanFactory beanFactory;
    
            @Override
            public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
                if (beanFactory instanceof ConfigurableListableBeanFactory) {
                    this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
                }
            }
    
            @Override
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                    BeanDefinitionRegistry registry) {
                if (this.beanFactory == null) {
                    return;
                }
                // 往Spring容器中注册一个WebServerFactoryCustomizerBeanPostProcessor
                registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
                        WebServerFactoryCustomizerBeanPostProcessor.class,
                        WebServerFactoryCustomizerBeanPostProcessor::new);
                registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
                        ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
            }
    
            private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name,
                    Class<T> beanClass, Supplier<T> instanceSupplier) {
                if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
                    RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier);
                    beanDefinition.setSynthetic(true);
                    registry.registerBeanDefinition(name, beanDefinition);
                }
            }
    
        }
    
    }
    

    我们以EmbeddedTomcat这个类为例:

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
    @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    static class EmbeddedTomcat {
    
        @Bean
        TomcatServletWebServerFactory tomcatServletWebServerFactory(
                ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
                ObjectProvider<TomcatContextCustomizer> contextCustomizers,
                ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); //这里new出来使用的是默认的端口8080
    
            // orderedStream()调用时会去Spring容器中找到TomcatConnectorCustomizer类型的Bean,默认是没有的,程序员可以自己定义
            factory.getTomcatConnectorCustomizers()
                    .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
            factory.getTomcatContextCustomizers()
                    .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
            factory.getTomcatProtocolHandlerCustomizers()
                    .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
            return factory;
        }
    
    }
    

    只有当spring容器中没有ServletWebServerFactory,并且所依赖的三个类也都存在时,才会创建TomcatServletWebServerFactory。

    3.关于application.properties属性是如何替换默认值

    BeanPostProcessorsRegistrar.class当中,会调用registerBeanDefinitions()向spring容器中注册WebServerFactoryCustomizerBeanPostProcessor。

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
        if (this.beanFactory == null) {
            return;
        }
        // 往Spring容器中注册一个WebServerFactoryCustomizerBeanPostProcessor
        registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
                WebServerFactoryCustomizerBeanPostProcessor.class,
                WebServerFactoryCustomizerBeanPostProcessor::new);
        registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
                ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
    }
    
    

    然后会接着调用WebServerFactoryCustomizerBeanPostProcessor#postProcessBeforeInitialization()方法

    private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
        // 获取WebServerFactoryCustomizer对WebServerFactory进行自定义,默认会拿到5个,其中就包括ServletWebServerFactoryCustomizer
        LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
                .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
                .invoke((customizer) -> customizer.customize(webServerFactory));
    }
    

    最终会执行对应的customize(),读取properties文件中配置的信息,替换默认值:

    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
        map.from(this.serverProperties::getPort).to(factory::setPort);
        map.from(this.serverProperties::getAddress).to(factory::setAddress);
        map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
        map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
        map.from(this.serverProperties.getServlet()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);
        map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
        map.from(this.serverProperties::getSsl).to(factory::setSsl);
        map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
        map.from(this.serverProperties::getCompression).to(factory::setCompression);
        map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
        map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
        map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
        map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
        for (WebListenerRegistrar registrar : this.webListenerRegistrars) {
            registrar.register(factory);
        }
        if (!CollectionUtils.isEmpty(this.cookieSameSiteSuppliers)) {
            factory.setCookieSameSiteSuppliers(this.cookieSameSiteSuppliers);
        }
    }
    

    4.通过自定义TomcatConnectorCustomizer更改tomcat信息

    在TomcatServletWebServerFactory#getWebServer,其中customizeConnector就会调用之前设置到factory里面的自定义的TomcatConnectorCustomizer,然后对connector进行配置:

    public WebServer getWebServer(ServletContextInitializer... initializers) {
        if (this.disableMBeanRegistry) {
            Registry.disableRegistry();
        }
        Tomcat tomcat = new Tomcat();
        File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        for (LifecycleListener listener : this.serverLifecycleListeners) {
            tomcat.getServer().addLifecycleListener(listener);
        }
        Connector connector = new Connector(this.protocol);
        connector.setThrowOnFailure(true);
        tomcat.getService().addConnector(connector);
        // 配置tomcat端口号
        customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        configureEngine(tomcat.getEngine());
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        prepareContext(tomcat.getHost(), initializers);
        return getTomcatWebServer(tomcat);// 这里启动tomcat
    }
    
    protected void customizeConnector(Connector connector) {
        int port = Math.max(getPort(), 0);
        connector.setPort(port);
        if (StringUtils.hasText(getServerHeader())) {
            connector.setProperty("server", getServerHeader());
        }
        if (connector.getProtocolHandler() instanceof AbstractProtocol) {
            customizeProtocol((AbstractProtocol<?>) connector.getProtocolHandler());
        }
        invokeProtocolHandlerCustomizers(connector.getProtocolHandler());
        if (getUriEncoding() != null) {
            connector.setURIEncoding(getUriEncoding().name());
        }
        // Don't bind to the socket prematurely if ApplicationContext is slow to start
        connector.setProperty("bindOnInit", "false");
        if (getHttp2() != null && getHttp2().isEnabled()) {
            connector.addUpgradeProtocol(new Http2Protocol());
        }
        if (getSsl() != null && getSsl().isEnabled()) {
            customizeSsl(connector);
        }
        TomcatConnectorCustomizer compression = new CompressionConnectorCustomizer(getCompression());
        compression.customize(connector);
        // 这个customizer就是程序员自己定义的bean,然后覆盖默认的值
        for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
            customizer.customize(connector);
        }
    }
    
    
    // 示例
    // 通过自定义TomcatConnectorCustomizer,实现更改tomcat的信息
    @Bean
    public TomcatConnectorCustomizer tomcatConnectorCustomizer(){
        return new TomcatConnectorCustomizer() {
            @Override
            public void customize(Connector connector) {
                connector.setPort(8082);
            }
        };
    }
    

    相关文章

      网友评论

          本文标题:SpringBoot自动装配

          本文链接:https://www.haomeiwen.com/subject/zatdcdtx.html