您的位置 首页 java

Java Web轻松学30 – MVC使用Java配置DispatcherServlet整合IoC

本系列文章旨在记录和总结自己在Java Web开发之路上的知识点、经验、问题和思考,原来已经分享在我的CSDN博客,现在分享在头条,希望能帮助更多码农和想成为码农的人。版权声明:本文为CSDN博主「普通的码农」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。原文链接:
 

目录

  1. 介绍
  2. 使用WebApplicationInitializer接口
  3. 使用Abstract DispatcherServlet Initializer 抽象类
  4. 使用AbstractContextLoaderInitializer抽象类
  5. 总结

介绍

介绍了基于XML来配置Spring MVC的DispatcherServlet并整合Spring IoC容器,本篇文章继续介绍Spring MVC提供的基于Java的方式来配置DispatcherServlet并整合Spring IoC容器。

我们仍然使用上篇文章的示例工程。

使用基于Java的方式进行配置的基本步骤,就是要实现 Spring MVC提供的某个接口或扩展某个抽象类,往往扩展抽象类会更简单更清晰一些;然后覆盖某些方法即可。

这些接口和抽象类的名字都是以 Initializer 结尾的,我们就叫它们为 初始化器 吧。

Spring MVC会自动扫描是否有初始化器的 具体类 ,如果有,就会自动实例化它们并执行相应的方法来配置DispatcherServlet并整合Spring IoC容器。

而且,基于XML和基于Java这两种方式可以同时使用。

使用WebApplicationInitializer接口

我们先使用实现WebApplicationInitializer接口的方式来配置DispatcherServlet并整合Spring IoC容器。

首先,假设我们要为spring-mvc-test工程的 appA应用 使用基于Java的方式来配置DispatcherServlet并整合Spring IoC容器。

先把web.xml中的关于appA的相关配置注释掉或删掉,我这里选择注释(使用<!–和–>):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns=" java ee"
xmlns:xsi=""
xsi:schemaLocation=" 
"
id="WebApp_ID" version="3.0">

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>context config Location</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<!-- 注释掉appA的相关配置
<servlet>
<servlet-name>appA</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/appA-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appA</ Servlet -name>
<url-pattern>/appA/*</url-pattern>
</servlet-mapping>
 -->
<servlet>
<servlet-name>appB</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/appB-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appB</servlet-name>
<url-pattern>/appB/*</url-pattern>
</servlet-mapping>
</web-app>
 

1.新建类AppAInitializer

我把新建的这个初始化器类放到test.config包下,你也可以放在自己定义的包下,AppAInitializer.java的代码如下:

package test.config;
import javax.servlet. ServletContext ;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class AppAInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
XmlWebApplicationContext appAContext = new XmlWebApplicationContext();
appAContext.setConfigLocation("/WEB-INF/appA-context.xml");
 ServletRegistration.Dynamic registrationA = container.addServlet("appA", new DispatcherServlet(appAContext));
 registrationA.setLoadOnStartup(1);
 registrationA.addMapping("/appA/*");
}
}
 

WebApplicationInitializer接口有唯一的方法onStartup需要我们实现。那怎么实现呢?

2.实例化Spring IoC 容器

还记得我们在standalone应用中是如何在main方法中实例化Spring IoC容器的吗?

没错,就是使用ClassPathXmlApplicationContext来实例化一个ApplicationContext对象,参考 。

同样,在Web应用中也是类似,只不过Spring MVC为我们提供的是WebApplicationContext这个接口,如果配置元数据是基于XML的,那么我们就可以使用XmlWebApplicationContext这个具体类,我们实例化一个它的对象,然后设置它的配置元数据的位置即可(这个位置默认是从资源的根目录开始)。

XmlWebApplicationContext appAContext = new XmlWebApplicationContext();
appAContext.setConfigLocation("/WEB-INF/appA-context.xml");
 

3.动态注册DispatcherServlet

我们直接实例化一个DispatcherServlet对象,别忘了把我们前面生成的IoC容器传给它,这个IoC容器就是它的 Servlet IoC容器 了:

new DispatcherServlet(appAContext)
 

接下来,就应该配置DispatcherServlet了,这里,主要采用的是Servlet规范中的动态注册Servlet的API,即接口ServletContext的addServlet方法,ServletContext对象container是onStartup方法的参数:

ServletRegistration.Dynamic registrationA = container.addServlet("appA", new DispatcherServlet(appAContext));
 

最后,使用得到的注册对象设置Servlet的其他属性,比如是否容器启动时加载、URL映射模式等:

 registrationA.setLoadOnStartup(1);
 registrationA.addMapping("/appA/*");
 

4.验证

同上篇文章,不再赘述。

结论是整个Web应用可以由Tomcat正常加载并运行,包括Java配置的appA应用和原来web.xml中配置的appB应用。

如果完全不用web.xml配置呢?

那就把web.xml中的内容都注释或删除。

然后,可以仍然在AppAInitializer的onStartup方法中添加appB应用以及Root IoC容器的配置代码,不过这样的话代码会显得有些臃肿且不明确,记住,一个类只干一件事。

当然,也可以为appB应用创建独立的初始化器AppBInitializer,然后实现onStartup方法;

为Root IoC容器的配置创建独立的初始化器MyWebApplicationInitializer,然后实现onStartup方法。这里的类名都可以自由命名的。

AppBInitializer跟AppAInitializer类似,读者可以自行实现。

Root IoC容器则因为使用的是监听器而非Servlet,而有所不同。我们可以根据上面的动态注册Servlet的代码举一反三,既然有addServlet方法,是否也会有 addListener 方法呢?答案是肯定的,我们可以使用Eclipse的代码补全功能可以很快的找到这个方法(其他IDE都应该有此功能)。于是,我们应该先new一个Spring MVC提供的 ContextLoaderListener ,将Root IoC容器的配置元数据的位置传给这个监听器即可:

XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
rootContext.setConfigLocation("/WEB-INF/root-context.xml");
container.addListener(new ContextLoaderListener(rootContext));
 

使用AbstractDispatcherServletInitializer抽象类

上面覆盖WebApplicationInitializer接口的onStartup方法的方式感觉不够简练,所以Spring MVC为我们提供了更方便的AbstractDispatcherServletInitializer抽象类来配置DispatcherServlet并整合Spring IoC容器。

实际上,这个抽象类里面也可以配置Root IoC容器,不过这个抽象类也是通过继承 AbstractContextLoaderInitializer 抽象类的,因此我们也可以直接使用AbstractContextLoaderInitializer抽象类来配置Root IoC容器,见下一节。

我为appB应用的DispatcherServlet创建了一个独立的初始化器,AppBInitializer.java:

package test.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class AppBInitializer extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext appBContext = new XmlWebApplicationContext();
appBContext.setConfigLocation("/WEB-INF/appB-context.xml");
return appBContext;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/appB/*" };
}
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
@Override
protected String getServletName() {
return "appB";
}
}
 

我们必须要覆盖三个方法:

  • createServletApplicationContext:创建Servlet IoC容器的实例并传入配置元数据的位置;
  • getServletMappings:返回Servlet的URL映射模式;
  • createRootApplicationContext:创建Root IoC容器的实例并传入配置元数据的位置,我这里直接返回null,因为我下一节直接使用AbstractContextLoaderInitializer抽象类来配置Root IoC容器。

我还覆盖了一个方法:

  • getServletName:返回Servlet的名字即可,如果不覆盖此方法,会使用AbstractDispatcherServletInitializer抽象类默认的名字DEFAULT_SERVLET_NAME = “dispatcher”。大家可以自行看它的源码(如何查看源码参考 )。

一开始我并没有覆盖此方法,但是验证的时候我发现Console视图中 打印的日志信息是初始化dispatcher这个DispatcherServlet ,于是就想该如何使用AbstractDispatcherServletInitializer抽象类配置Servlet的名字,于是就查看了一下其源码。

使用AbstractContextLoaderInitializer抽象类

AbstractContextLoaderInitializer抽象类与上一节的AbstractDispatcherServletInitializer抽象类的配置模式是一样的,都是覆盖某些方法而已,不再赘述,直接上代码。

MyWebApplicationInitializer.java:

package test.config;
import org.springframework.web.context.AbstractContextLoaderInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class MyWebApplicationInitializer extends AbstractContextLoaderInitializer {
@Override
protected WebApplicationContext createRootApplicationContext() {
XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
rootContext.setConfigLocation("/WEB-INF/root-context.xml");
return rootContext;
}
}
 

总结

  • 基于Java和基于XML在一个Web应用中可以混合使用;
  • 基于Java的方式又有两种:WebApplicationInitializer接口和AbstractDispatcherServletInitializer抽象类;
  • 基于Java的整合Spring IoC的思想是一致的:都是先new一个容器对象,设置元数据的所在位置,然后把容器对象传给DispatcherServlet或ContextLoaderListener对象。
  • 我们要善于举一反三,触类旁通,推此及彼。
  • 我们要多看源代码和Javadoc。

文章来源:智云一二三科技

文章标题:Java Web轻松学30 – MVC使用Java配置DispatcherServlet整合IoC

文章地址:https://www.zhihuclub.com/186553.shtml

关于作者: 智云科技

热门文章

网站地图