spring boot 核心实现源码分析–开启一个web应用

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

通过分析demo程序源码来掌握技术的本质

    @SpringBootApplication
    @RestController
    public class DemoApplication {
        @RequestMapping("/")
        String home(){
            return "hello spring-boot and spring cloud";
        }
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

这里有几个地方是值得我们关注的,首先是三个注解,然后是SpringApplication这个类。首先来看看SpringApplication这个类的实现方式

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
            return run(new Class[]{primarySource}, args);
        }

这个方法返回的是一个ConfigurableApplicationContext类型的上下文
继续看run方法

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
            return (new SpringApplication(primarySources)).run(args);
        }

继续看

    public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
            this.configureHeadlessProperty();
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.starting();

            Collection exceptionReporters;
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
                this.configureIgnoreBeanInfo(environment);
                Banner printedBanner = this.printBanner(environment);
                context = this.createApplicationContext();
                exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
                this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                this.refreshContext(context);
                this.afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
                }

                listeners.started(context);
                this.callRunners(context, applicationArguments);
            } catch (Throwable var10) {
                this.handleRunFailure(context, var10, exceptionReporters, listeners);
                throw new IllegalStateException(var10);
            }

            try {
                listeners.running(context);
                return context;
            } catch (Throwable var9) {
                this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
                throw new IllegalStateException(var9);
            }
        }

这是调用的主run函数,首先开启SpringApplicationRunListeners监听器

        class SpringApplicationRunListeners {
            private final Log log;
            private final List<SpringApplicationRunListener> listeners;

            SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
                this.log = log;
                this.listeners = new ArrayList(listeners);
            }
            public void starting() {
                Iterator var1 = this.listeners.iterator();

                while(var1.hasNext()) {
                    SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
                    listener.starting();
                }

            }
        }

然后创建了一个应用上下文ConfigurableApplicationContext

    public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
        String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
        String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
        String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
        String ENVIRONMENT_BEAN_NAME = "environment";
        String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
        String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

        void setId(String var1);

        void setParent(@Nullable ApplicationContext var1);

        void setEnvironment(ConfigurableEnvironment var1);

        ConfigurableEnvironment getEnvironment();

        void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);

        void addApplicationListener(ApplicationListener<?> var1);

        void addProtocolResolver(ProtocolResolver var1);

        void refresh() throws BeansException, IllegalStateException;

        void registerShutdownHook();

        void close();

        boolean isActive();

        ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
    }

通过这个上下文加载应用所需的类和各种环境配置等,最后启动一个实例。也就是说,springboot在创建应用的时候,将springmvc中原本需要程序猿自己配的环境设置,交给了程序来完成。现在来看看程序是如何进行配置的以及我们如何去修改这些配置。

    context = this.createApplicationContext();

根据这句代码,找到ConfigurableApplicationContext这个方法

    protected ConfigurableApplicationContext createApplicationContext() {
            Class<?> contextClass = this.applicationContextClass;
            if (contextClass == null) {
                try {
                    switch(this.webApplicationType) {
                    case SERVLET:
                        contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                        break;
                    case REACTIVE:
                        contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                        break;
                    default:
                        contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                    }
                } catch (ClassNotFoundException var3) {
                    throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
                }
            }

            return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
        }

Class.forName是通过反射的方式来调用需要的class,根据this.webApplicationType进行判断,

    switch(this.webApplicationType) {
                    case SERVLET:
                        contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                        break;
                    case REACTIVE:
                        contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                        break;
                    default:
                        contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                    }

也就是说,是按照这三个类进行配置的

    AnnotationConfigServletWebServerApplicationContext
    AnnotationConfigReactiveWebServerApplicationContext
    AnnotationConfigApplicationContext

最后的结果通过BeanUtils.instantiateClass(contextClass);返回

    public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
            Assert.notNull(clazz, "Class must not be null");
            if (clazz.isInterface()) {
                throw new BeanInstantiationException(clazz, "Specified class is an interface");
            } else {
                try {
                    Constructor<T> ctor = KotlinDetector.isKotlinType(clazz) ? BeanUtils.KotlinDelegate.getPrimaryConstructor(clazz) : clazz.getDeclaredConstructor();
                    return instantiateClass(ctor);
                } catch (NoSuchMethodException var2) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", var2);
                } catch (LinkageError var3) {
                    throw new BeanInstantiationException(clazz, "Unresolvable class definition", var3);
                }
            }
        }

核心代码如下:

    Constructor<T> ctor = KotlinDetector.isKotlinType(clazz) ? BeanUtils.KotlinDelegate.getPrimaryConstructor(clazz) : clazz.getDeclaredConstructor();
    return instantiateClass(ctor);

这里似乎用到了kotlin,触及到了我的知识盲区,可以盲目分析一波,应该是对某些特定的情况进行排除,然后再来看看return instantiateClass(ctor);中的这个方法:ctor是一个构造器

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
            Assert.notNull(ctor, "Constructor must not be null");

            try {
                ReflectionUtils.makeAccessible(ctor);
                return KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ? BeanUtils.KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args);
            } catch (InstantiationException var3) {
                throw new BeanInstantiationException(ctor, "Is it an abstract class?", var3);
            } catch (IllegalAccessException var4) {
                throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var4);
            } catch (IllegalArgumentException var5) {
                throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var5);
            } catch (InvocationTargetException var6) {
                throw new BeanInstantiationException(ctor, "Constructor threw exception", var6.getTargetException());
            }
        }

看看核心代码:

    ReflectionUtils.makeAccessible(ctor);
    return KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ? BeanUtils.KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args);
    public static void makeAccessible(Constructor<?> ctor) { if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) { ctor.setAccessible(true); } }

感觉上是创建应用的构造器,并使构造器可用。来看看run函数中下面三句代码:

    this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    this.refreshContext(context);
    this.afterRefresh(context, applicationArguments);

第一句代码中传入了构造器,监听器,环境

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);

来看看这三个函数

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
            context.setEnvironment(environment);
            this.postProcessApplicationContext(context);
            this.applyInitializers(context);
            listeners.contextPrepared(context);
            if (this.logStartupInfo) {
                this.logStartupInfo(context.getParent() == null);
                this.logStartupProfileInfo(context);
            }

            context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
            if (printedBanner != null) {
                context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
            }
            Set<Object> sources = this.getAllSources();
            Assert.notEmpty(sources, "Sources must not be empty");
            this.load(context, sources.toArray(new Object[0]));
            listeners.contextLoaded(context);
        }

其中this.load(context, sources.toArray(new Object[0]));将调用

    protected void load(ApplicationContext context, Object[] sources) {
            if (logger.isDebugEnabled()) {
                logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
            }

            BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
            if (this.beanNameGenerator != null) {
                loader.setBeanNameGenerator(this.beanNameGenerator);
            }

            if (this.resourceLoader != null) {
                loader.setResourceLoader(this.resourceLoader);
            }

            if (this.environment != null) {
                loader.setEnvironment(this.environment);
            }

            loader.load();
        }
        //BeanDefinitionLoader 加载应用定义的和需要的类及各种资源
        public int load() {
            int count = 0;
            Object[] var2 = this.sources;
            int var3 = var2.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                Object source = var2[var4];
                count += this.load(source);
            }

            return count;
        }
        //
        private int load(Object source) {
            Assert.notNull(source, "Source must not be null");
            if (source instanceof Class) {
                return this.load((Class)source);
            } else if (source instanceof Resource) {
                return this.load((Resource)source);
            } else if (source instanceof Package) {
                return this.load((Package)source);
            } else if (source instanceof CharSequence) {
                return this.load((CharSequence)source);
            } else {
                throw new IllegalArgumentException("Invalid source type " + source.getClass());
            }
        }
        //
        private int load(Class<?> source) {
            if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
                BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
                this.load(loader);
            }

            if (this.isComponent(source)) {
                this.annotatedReader.register(new Class[]{source});
                return 1;
            } else {
                return 0;
            }
        }
        //
        private int load(BeanDefinitionLoader.GroovyBeanDefinitionSource source) {
            int before = this.xmlReader.getRegistry().getBeanDefinitionCount();
            ((GroovyBeanDefinitionReader)this.groovyReader).beans(source.getBeans());
            int after = this.xmlReader.getRegistry().getBeanDefinitionCount();
            return after - before;
        }
        //
        private boolean isComponent(Class<?> type) {
            if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
                return true;
            } else {
                return !type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass() && type.getConstructors() != null && type.getConstructors().length != 0;
            }
        }

通过上面的一系列方法,实现了强大的自动配置功能

来看看@SpringBootApplication注解

    public @interface SpringBootApplication {
        @AliasFor(
            annotation = EnableAutoConfiguration.class
        )
        Class<?>[] exclude() default {};

        @AliasFor(
            annotation = EnableAutoConfiguration.class
        )
        String[] excludeName() default {};

        @AliasFor(
            annotation = ComponentScan.class,
            attribute = "basePackages"
        )
        String[] scanBasePackages() default {};

        @AliasFor(
            annotation = ComponentScan.class,
            attribute = "basePackageClasses"
        )
        Class<?>[] scanBasePackageClasses() default {};
    }
    //可以看出,包含了额外的三个注解,分别是:
    //@EnableAutoConfiguration、@ComponentScan和@SpringBootConfiguration

@EnableAutoConfiguration用于启动自动配置,倒入一些自动配置的类定义

    public @interface EnableAutoConfiguration {
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

        Class<?>[] exclude() default {};

        String[] excludeName() default {};
    }
    //包含了AutoConfigurationPackage

@ComponentScan 将扫描和加载应用中的一些自定义的类

    public @interface ComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; String resourcePattern() default "**/*.class"; boolean useDefaultFilters() default true; ComponentScan.Filter[] includeFilters() default {}; ComponentScan.Filter[] excludeFilters() default {}; boolean lazyInit() default false; @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Filter { FilterType type() default FilterType.ANNOTATION; @AliasFor("classes") Class<?>[] value() default {}; @AliasFor("value") Class<?>[] classes() default {}; String[] pattern() default {}; } }

在架包里面

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
    org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
    org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
    org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
    org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
    org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
    org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
    org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
    org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
    org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
    org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
    org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
    org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
    org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
    org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
    org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
    org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
    org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
    org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
    org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
    org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
    org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
    org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
    org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
    org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
    org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
    org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
    org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
    org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
    org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
    org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
    org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
    org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
    org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
    org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
    org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
    org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
    org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
    org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
    org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
    org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
    org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
    org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
    org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
    org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
    org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
    org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
    org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
    org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

在主程序中使用注解@Configuration 注解来代替@SpringBootApplication注解,然后使用@Import指定需要加载的配置类。
类似于这样的方法

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import({AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

        Class<?>[] exclude() default {};

        String[] excludeName() default {};
    }

修改的demo

    @Configuration
    @Import({
        WebClientAutoConfiguration.class,
        HttpEncodingAutoConfiguration.class
        ...
    })
    @RestController
    public class Application{
        @RequestMapping("/")
        String home(){
            return "hello";
       }
    }

来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring boot 核心实现源码分析–开启一个web应用

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏