SpringMVC的注解配置原理

META-INF\services\javax.servlet.ServletContainerInitializer

web容器启动的时候,会扫描每个jar包中META-INF\services\javax.servlet.ServletContainerInitializer文件, 加载其中指定的ServletContainerInitializer的实现类,并调用onStartup方法。@HandlesTypes(value = {HelloServlet.class})用于指定一个接口,所有该接口的实现类会传给onStartup方法的第一个参数。

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

在这里插入图片描述

package com.example.demo3

// HelloServlet是个接口,我例子中的实现类就不贴出来了
@HandlesTypes(value = {HelloServlet.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {

    /**
     * 应用启动的时候,会运行onStartup
     * @param c @HandlesTypes注解中配置的接口的所有实现类
     * @param ctx 可以用来注册三大组件
     * @throws ServletException
     */
    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        System.out.println("onStartup");
        for (Class<?> aClass : c) {
            System.out.println(aClass);
        }
    }
}

在这里插入图片描述

配置web三大组件

@HandlesTypes(value = {HelloServlet.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        System.out.println("onStartup");
        for (Class<?> aClass : c) {
            System.out.println(aClass);
        }

        //形式注册三大组件
        
        //注册组件  ServletRegistration
        ServletRegistration.Dynamic servlet = ctx.addServlet("servletDemo4", new ServletDemo4());
        //配置servlet的映射信息
        servlet.addMapping("/demo4");

        //注册Listener
        ctx.addListener(MyServletContextListener.class);

        //注册Filter  FilterRegistration
        FilterRegistration.Dynamic filter = ctx.addFilter("filterDemo1", FilterDemo1.class);
        //配置Filter的映射信息
        filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
    }
}

过滤器:

public class FilterDemo1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter-init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter-doFilter");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("Filter-destroy");
    }
}

监听器:

public class MyServletContextListener implements ServletContextListener {

    /**
     * 监听ServletContext对象创建
     * @param sce
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyServletContextListener-contextInitialized");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}

Servlet程序:

public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo4");
    }
}

Spring整合SpringMVC

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.2.RELEASE</version>
</dependency>

在这里插入图片描述
从上面加载的spring-web的jar包中可以看到,也配置了javax.servlet.ServletContainerInitializer,内容是org.springframework.web.SpringServletContainerInitializer,所以,Spring启动的时候,会加载org.springframework.web.SpringServletContainerInitializer类,并调用onStartup方法,这个类的源码如下:

// 会加载所有WebApplicationInitializer的实现类给onStartup方法的webAppInitializerClasses参数
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    public SpringServletContainerInitializer() {
    }

    public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
        List<WebApplicationInitializer> initializers = new LinkedList();
        Iterator var4;
        if (webAppInitializerClasses != null) {
            var4 = webAppInitializerClasses.iterator();

            while(var4.hasNext()) {
                Class<?> waiClass = (Class)var4.next();
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((WebApplicationInitializer)waiClass.newInstance());
                    } catch (Throwable var7) {
                        throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
                    }
                }
            }
        }

        if (initializers.isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
        } else {
            servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
            AnnotationAwareOrderComparator.sort(initializers);
            var4 = initializers.iterator();

            while(var4.hasNext()) {
                WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
                initializer.onStartup(servletContext);
            }

        }
    }
}

现在来看看WebApplicationInitializer的实现类有哪些:
在这里插入图片描述

  • AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器
  • AbstractContextLoaderInitializer :创建 根容器
  • AbstractDispatcherServletInitializer
    创建web ioc容器
    创建DispatcherServlet
    将创建的DispatcherServlet添加到ServletContext中

所以,如果我们希望以注解的方式来启动SpringMVC,就继承 AbstractAnnotationConfigDispatcherServletInitializer类,实现抽象方法,具体如何配置请看官网(https://docs.spring.io/spring/docs/),这里只是讨论了注解配置的基本原理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值