Spring中WebApplicationInitializer的理解

现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代,它是一个接口。通过实现WebApplicationInitializer,在其中可以添加servlet,listener等,在加载Web项目的时候会加载这个接口实现类,从而起到web.xml相同的作用。下面就看一下这个接口的详细内容。

首先打开这个接口,如下:

public interface WebApplicationInitializer {
    void onStartup(ServletContext var1) throws ServletException;
}

只有一个方法,看不出什么头绪。但是,在这个包下有另外一个类,SpringServletContainerInitializer。它的实现如下:

package org.springframework.web;

import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

@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);
            }

        }
    }
}

这个类就比较有意思了,先不管其他的,读一下这段代码,可以得到这样的意思。

先判断webAppInitializerClasses这个Set是否为空。如果不为空的话,找到这个set中不是接口,不是抽象类,并且是

WebApplicationInitializer接口实现类的类,将它们保存到list中。当这个list为空的时候,抛出异常。不为空的话就按照一定的顺序排序,并将它们按照一定的顺序实例化。调用其onStartup方法执行。到这里,就可以解释WebApplicationInitializer实现类的工作过程了。但是,在web项目运行的时候,SpringServletContainerInitializer这个类又是怎样被调用的呢。

它只有一个接口,ServletContainerInitializer,通过它就可以解释SpringServletContainerInitializer是如何被调用的。它的内容如下:

package javax.servlet;

import java.util.Set;

public interface ServletContainerInitializer {
    void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException;
}

首先,这个接口是javax.servlet下的。官方的解释是这样的:为了支持可以不使用web.xml。提供了ServletContainerInitializer,它可以通过SPI机制,当启动web容器的时候,会自动到添加的相应jar包下找到META-INF/services下以ServletContainerInitializer的全路径名称命名的文件,它的内容为ServletContainerInitializer实现类的全路径,将它们实例化。既然这样的话,那么SpringServletContainerInitializer作为ServletContainerInitializer的实现类,它的jar包下也应该有相应的文件。打开查看如下:

哈,现在就可以解释清楚了。首先,SpringServletContainerInitializer作为ServletContainerInitializer的实现类,通过SPI机制,在web容器加载的时候会自动的被调用。(这个类上还有一个注解@HandlesTypes,它的作用是将感兴趣的一些类注入到ServletContainerInitializerde), 而这个类的方法又会扫描找到WebApplicationInitializer的实现类,调用它的onStartup方法,从而起到启动web.xml相同的作用。

然后,我们自己通过一个实例来实现相同的功能,通过一样的方式来访问一个servlet。

1、定义接口WebParameter,它就相当于WebApplicationInitializer。内容如下:

public interface WebParameter {

    void loadOnstarp(ServletContext servletContext);
}

可以在这里面添加servlet,listener等。

2、定义Servlet。

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("TestSetvlet");
    }
}

3、定义MyWebParameter作为WebParameter的实现类,将Servlet添加到上下文,并设置好映射。

public class MyWebParameter implements WebParameter {
    public void loadOnstarp(ServletContext servletContext) {
        ServletRegistration.Dynamic testSetvelt=servletContext.addServlet("test","com.test.servlet.MyServlet");
        testSetvelt.setLoadOnStartup(1);
        testSetvelt.addMapping("/test");
    }
}

当然,也可以把第2步和第3步合在一起:

public class MyServlet extends HttpServlet implements WebParameter {

    @Override
    public void loadOnstarp(ServletContext servletContext) {
        ServletRegistration.Dynamic testSetvelt=servletContext.addServlet("test","com.test.servlet.MyServlet");
        testSetvelt.setLoadOnStartup(1);
        testSetvelt.addMapping("/test");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("TestSetvlet");
    }
}

而且以后可以将Spring的applicationContext.xml与web.xml融合在一个类中。即注解为@Configuration,并实现WebApplicationInitializer。

4、定义好WebConfig作为ServletContainerInitializer的实现类,它的作用是扫描找到WebParameter的实现类,并调用其方法。

@HandlesTypes({WebParameter.class})
public class WebConfig implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        Iterator var4;
        if (set!=null){
            var4=set.iterator();
            while(var4.hasNext()){
                Class<?> clazz= (Class<?>) var4.next();
                if (!clazz.isInterface()&& !Modifier.isAbstract(clazz.getModifiers())&&WebParameter.class.isAssignableFrom(clazz)){
                    try {
                        ((WebParameter) clazz.newInstance()).loadOnstarp(servletContext);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

5、根据SPI机制,定义一个META-INF/services文件夹,并在其下定义相关文件名称,并将WebConfig的类全名称填入其中。

6、最终结果:

本文转自:https://blog.csdn.net/zq17865815296/article/details/79464403

原文地址:https://www.cnblogs.com/nizuimeiabc1/p/11031150.html

时间: 2024-10-15 21:33:12

Spring中WebApplicationInitializer的理解的相关文章

Spring中Bean的理解以及@Bean的作用

一.Bean是啥 1.Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化): 2.凡是有方法或属性的类都需要实例化,这样才能具象化去使用这些方法和属性: 3.规律:凡是子类及带有方法或属性的类都要加上注册Bean到Spring IoC的注解: 4.把Bean理解为类的代理或代言人(实际上确实是通过反射.代理来实现的),这样它就能代表类拥有该拥有的东西了 5.我们都在微博上@过某某,对方会优先看到这条信息,并给你反馈,那么在Spring中,你标识一个@符号,那么Spr

Spring中AOP的理解

1.AOP的概念 AOP(AspectOriented Programming,面向切面编程)指的是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下个程序动态统一添加功能的一种技术.AOP提供从一个角度来考虑程序结构以完善面向对象编程.它为开发人员提供了一种描述横切关注点的机制,并能够自动将横向关注点入到面向对象的软件系统中,从而实现了横切关注点模块化 AOP一般用于实现那些与业务无关,但是业务模块所共同调用的逻辑,例如异常拦截.事务管理.日志管理和权限控制等,AOP将这些代码封装起

spring中的ResponseEntity理解

参考: https://blog.csdn.net/weixin_37869477/article/details/82762976 https://blog.csdn.net/sswqzx/article/details/84938223 ResponseEntity可以定义返回的HttpStatus(状态码)和HttpHeaders(消息头:请求头和响应头) HttpStatus(状态码)https://blog.csdn.net/csdn1844295154/article/details

Spring中Bean及@Bean的理解

Bean在Spring和SpringMVC中无所不在,将这个概念内化很重要,下面分享一下我的想法: 一.Bean是啥 1.Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化): 2.凡是有方法或属性的类都需要实例化,这样才能具象化去使用这些方法和属性: 3.规律:凡是子类及带有方法或属性的类都要加上注册Bean到Spring IoC的注解: 4.把Bean理解为类的代理或代言人(实际上确实是通过反射.代理来实现的),这样它就能代表类拥有该拥有的东西了 5.我们都在微

事务理解及Spring中的事务

一.隔离级别理解 1.脏读 首先理解,一个事务对数据进行了改变,尽管该事务尚未提交,但此时其他语句查到的数据,是该事务修改之后的.验证如下: 一张简单的user表 我们运行下面的语句123三行,开启事务,但是尚未提交 我们可以看到即使该事务尚未提交,但是此时查到的也是事务修改后的数据. 再看,运行如下56两行语句 所以,脏读,就是一个事务B读到的数据是另外一个事务A尚未提交的数据,这种情况称为脏读,因为如果A事务回滚了,那么B事务读取到的数据就是不正确的数据.  2.不可重复读取 不可重复读是指

深入理解spring中的各种注解

Spring中的注解大概可以分为两大类: 1)spring的bean容器相关的注解,或者说bean工厂相关的注解: 2)springmvc相关的注解. spring的bean容器相关的注解,先后有:@Required, @Autowired, @PostConstruct, @PreDestory,还有Spring3.0开始支持的JSR-330标准javax.inject.*中的注解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singlet

Spring中Adivisor和Aspect的区别(自我理解)

在AOP中有几个概念: - 方/切 面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象.事务管理是J2EE应用中一个很好的横切关注点例子.方面用Spring的Advisor或拦截器实现. - 连接点/织入点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出. - 通知(Advice):在特定的连接点,AOP框架执行的动作.各种类型的通知包括"around"."before"和"throws"通知

深入理解spring中的各种注解(转)

Spring中的注解大概可以分为两大类: 1)spring的bean容器相关的注解,或者说bean工厂相关的注解: 2)springmvc相关的注解. spring的bean容器相关的注解,先后有:@Required, @Autowired, @PostConstruct, @PreDestory,还有Spring3.0开始支持的JSR-330标准javax.inject.*中的注解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singlet

对Spring中IOC和DI的理解

前几篇讲了Spring中IOC和DI的用法,本篇应该放到三篇之前,但一直没有想到好的讲解方式,后参考https://blog.csdn.net/luoyepiaoxue2014/article/details/72426666博客,对其中涉及到的进行了简单的总结. 在学习Spring的过程中,总会涉及到两个概念---IOC和DI,即控制反转和依赖注入,而对这两个概念的理解也总是含糊不清的,下面就对自己的理解进行总结. 首先是IOC,即控制反转,需要理解的是:怎么控制?谁控制了什么?怎么反转?既然