美文网首页
Spring | SpringBoot是如何做到去xml的?

Spring | SpringBoot是如何做到去xml的?

作者: cengel | 来源:发表于2018-08-28 15:13 被阅读0次

    简单总结:

    1. Servlet3.0 onStartup()中初始化ApplictaionContext去web.xml
    2. 全注解,@Configuration去spring配置文件
    3. yaml 配置替换属性文件配置

    1. 全注解: 去ApplicationContext.xml

    使用configuration注解替换替换applicationContext.xml中的<beans>标签

    @Configuration //注解配置 - 相当于xml的<beans>标签
    @ComponentScan({ "com.cengel.cglab" })//启用组件扫描 - 不写将默认仅扫描此类所在包及其子包
    @Import({ HibernateConfig.class, RedisConfig.class, SpringRmiConfig.class })
    public class RootConfig {
        @Bean
        public Student student(){
            return new Student();
        }
    }   
    

    2. 内置web容器

    SpringBoot除了高度集成封装了Spring一系列框架之外,还封装了web容器.
    SpringBoot支持嵌入tomcat jetty undertow三种web容器,查看EmbeddedServletContainerAutoConfiguration 类源码可知.

    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @Configuration
    @ConditionalOnWebApplication
    @Import(BeanPostProcessorsRegistrar.class)
    public class EmbeddedServletContainerAutoConfiguration {
    
        @Configuration
        @ConditionalOnClass({ Servlet.class, Tomcat.class })
        @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
        public static class EmbeddedTomcat {
            @Bean
            public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
                return new TomcatEmbeddedServletContainerFactory();
            }
        }
        @Configuration
        @ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
                WebAppContext.class })
        @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
        public static class EmbeddedJetty {
            @Bean
            public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
                return new JettyEmbeddedServletContainerFactory();
            }
        }
        @Configuration
        @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
        @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
        public static class EmbeddedUndertow {
            @Bean
            public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
                return new UndertowEmbeddedServletContainerFactory();
            }
        }
    // .. . 其他省略
    }
    

    在spring-boot-starter-web的pom中可以看到,springweb application默认使用的是tomcat容器.

    3.Servlet3.0去web.xml

    在Servlet3.0环境中,Web容器会在类路径(META-INF/services)目录下查找javax.servlet.ServletContainerInitilalizer文件(文件配置其实现类),web容器加载时,会执行该接口实现类的onStart方法

    1. 为什么在web项目代码中继承AbstractAnnotationConfigDispatcherServletInitializer该类,不需要配置web.xml,spring环境就能运行?

    1.实现javax.servlet.ServletContainerInitializer

    @HandlesTypes({WebApplicationInitializer.class})
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        public SpringServletContainerInitializer() {
        }
    
        public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
            //todo tomcat容器加载时,会执行,spring容器初始化在这里执行
            
            //存放spring-web项目的WebApplicationInitializer接口的所有实现类
            List<WebApplicationInitializer> initializers = new LinkedList<>();
    
            if (webAppInitializerClasses != null) {
                for (Class<?> waiClass : webAppInitializerClasses) {
                    //  查找spring-web项目的WebApplicationInitializer接口的所有实现类
                    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                            WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                        try {
                            initializers.add((WebApplicationInitializer)
                                    ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                        }
                        catch (Throwable ex) {
                            throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                        }
                    }
                }
            }
    
            if (initializers.isEmpty()) {
                servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
                return;
            }
    
            servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
            AnnotationAwareOrderComparator.sort(initializers);
            for (WebApplicationInitializer initializer : initializers) {
                //逐一执行这些实现类的onStartUp方法
                //一般Spring的ApplicationContext Configure Servlet Filter等都包含在这些实现类的中,调用onStart方法时,执行这些初始化
                initializer.onStartup(servletContext);
            }
            
        }
    }
       
    
    1. 在Spring-Web的jar包META-INF下配置该接口


      配置webServletContainerInitailizer实现类
    2. AbstractAnnotationConfigDispatcherServletInitializer 这个抽象类继承了WebApplicationInitializer
      也就是说,此类的onStart方法会在web容器加载时被执行
      而逐一向上查看此类的父类,onStart方法包含了Servlet Config Filter等的初始化
    public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer {
        public AbstractAnnotationConfigDispatcherServletInitializer() {
        }
    
        protected WebApplicationContext createRootApplicationContext() {
            Class<?>[] configClasses = this.getRootConfigClasses();
            if (!ObjectUtils.isEmpty(configClasses)) {
                AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
                rootAppContext.register(configClasses);
                return rootAppContext;
            } else {
                return null;
            }
        }
    
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
            Class<?>[] configClasses = this.getServletConfigClasses();
            if (!ObjectUtils.isEmpty(configClasses)) {
                servletAppContext.register(configClasses);
            }
    
            return servletAppContext;
        }
    
        //基于注解的bean配置类
        protected abstract Class<?>[] getRootConfigClasses();
        //基于注解的servlet配置类(webmvc viewResoler)
        protected abstract Class<?>[] getServletConfigClasses();
    }
    

    就这样,springbootApplication执行main方法时启动tomcat容器,tomcat容器初始化加载时,会执行ServletContainerInitializer的onStartup方法,Spring通过对该接口的实现,完成spring上下文,配置,servlet等的初始化装载.

    相关文章

      网友评论

          本文标题:Spring | SpringBoot是如何做到去xml的?

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