深入SpringBoot:自定义EnableAutoConfig

作者: wcong | 来源:发表于2016-06-06 17:45 被阅读17669次

    前言

    上面几篇文章介绍了SpringFramework的一些原理,这里开始介绍一下SpringBoot,并通过自定义一些功能来介绍SpringBoot的原理。SpringBoot在SpringFramework的基础上集成了Web容器,日志等功能,可以快速的实现Web服务。
    先看SpringBoot必要的依赖。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
    

    spring-boot包含了SpringBoot的核心实现类。
    spring-boot-autoconfigure则是根据当前classpath的类来注入不同的实现类。

    EnableAutoConfiguration

    先看一个基本的例子,这个例子实现了一个简单的web服务。

    1. 引入必要的依赖,开启web服务需要引入对应的EmbedWeb容器。
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
    
    1. 程序入口,这里使用了EnableAutoConfiguration注解。
        @Configuration
        @EnableAutoConfiguration
        public class Bootstrap {
            public static void main(String[] args) {
                SpringApplication springApplication = new SpringApplication(Bootstrap.class);
                springApplication.run(args);
            }
            @Controller
            public static class MyController {
                @RequestMapping
                @ResponseBody
                public Map index() {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("hello", "world");
                    return map;
                }
            }
        }
    

    观察EnableAutoConfiguration可以发现,这里ImportEnableAutoConfigurationImportSelector
    Import主要是配合Configuration来使用的,用来导出更多的Configuration类,ConfigurationClassPostProcessor会读取Import的内容来实现具体的逻辑。
    EnableAutoConfigurationImportSelector实现了DeferredImportSelector接口,并实现了selectImports方法,用来导出Configuration类。

        String[] selectImports(AnnotationMetadata importingClassMetadata);
    

    导出的类是通过SpringFactoriesLoader.loadFactoryNames()读取了ClassPath下面的META-INF/spring.factories文件,这个文件内容大致如下。

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
    ...
    org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
    ...
    

    其中EmbeddedServletContainerAutoConfiguration是实现web服务的主要的配置类。这个类会根据当前存在的类的信息注入必要的EmbeddedServletContainerFactory类。
    spring-boot-starter-tomcat引入了tomcat的依赖,所以EmbeddedServletContainerAutoConfiguration发现存在Tomcat.class就会注入TomcatEmbeddedServletContainerFactory来内置web容器。

        @Configuration
        @ConditionalOnClass({ Servlet.class, Tomcat.class })
        @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
        public static class EmbeddedTomcat {
            @Bean
            public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
                return new TomcatEmbeddedServletContainerFactory();
            }
        }
    

    自定义EnableAutoConfiguration

    自定义EnableAutoConfiguration就比较简单了。完整的代码在Github上了。

    1. 自定义EnableAutoConfiguration,这里ImportMyEnableAutoConfigurationImport
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Inherited
        @AutoConfigurationPackage
        @Import(MyEnableAutoConfigurationImport.class)
        public @interface MyEnableAutoConfiguration {
        }
    
    1. 自定义EnableAutoConfigurationImport,注入了ClassLoader,并调用SpringFactoriesLoader.loadFactoryNames()方法,导出Configuration的类。
        public class MyEnableAutoConfigurationImport implements DeferredImportSelector, BeanClassLoaderAware {
            private ClassLoader classLoader;
            public void setBeanClassLoader(ClassLoader classLoader) {
                this.classLoader = classLoader;
            }
            public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                List<String> beanNames = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader);
                return beanNames.toArray(new String[beanNames.size()]);
            }
        }
    
    1. 入口类,这里使用了MyEnableAutoConfiguration注解。
        @Configuration
        @MyEnableAutoConfiguration
        public class CustomizeEnableAutoConfigure {
            public static void main(String[] args) {
                SpringApplication application = new SpringApplication(CustomizeEnableAutoConfigure.class);
                application.run(args);
            }
            @Controller
            public static class MyController {
                @RequestMapping
                @ResponseBody
                public Map index() {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("hello", "world");
                    return map;
                }
            }
        }
    

    结语

    这里主要介绍了SpringBootEnableAutoConfiguration的实现,后面会介绍更多关于SpringBoot的内容。

    相关文章

      网友评论

        本文标题:深入SpringBoot:自定义EnableAutoConfig

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