我的Java Web之路 - Spring MVC(5)- 整合基于注解和Java的Spring IoC容器

介绍

前面这篇文章这篇文章里面,Spring MVC整合的都是基于XML来获取配置元数据的Spring IoC容器,但很多情况下我们想使用基于注解和Java来获取配置元数据的Spring IoC容器,没关系,Spring MVC也为我们提供了这种整合所需要的组件。

由于有了前面的基础,本篇文章不再把整个工程的结构以及所有代码都展示出来,只把有关的部分代码展示出来,因为编写方式都是类似的,读者可以尝试自己在原来的代码基础上进行修改和验证。

思路

如何整合呢?我们先来看看原来在基于Java配置DispatcherServlet的代码中是如何整合Spring IoC容器的:

		XmlWebApplicationContext appBContext = new XmlWebApplicationContext();
		appBContext.setConfigLocation("/WEB-INF/appB-context.xml");

关键在于XmlWebApplicationContext这个类的前缀是Xml,那我们是不是可以猜想有类似于JavaWebApplicationContext或者AnnotationWebApplicationContext这样的类呢?然后不就可以生成它们的实例,传入配置元数据的位置了吗?

不过根据这篇文章,传入的配置元数据的位置就不是XML文件的目录了,而是一个带有@Configuration注解的一个配置类了。可能方法名称还是setConfigLocation,但也可能是别的。

现在问题是确定有没有JavaWebApplicationContext或者AnnotationWebApplicationContext这样的类。我们先看XmlWebApplicationContext所在的包是哪:

import org.springframework.web.context.support.XmlWebApplicationContext;

可以看到,它在org.springframework.web包下,于是很自然的想到可以在 spring-web-5.1.7.RELEASE.jar 包中去找。我们在Eclipse的 Project Explorer 视图中打开所依赖的该JAR包,一级一级往下找:
spring-web JAR包中寻找类.png
继续展开context节点及其子节点support:
spring-web JAR包中寻找类1.png
可以看到,除了我们已经使用过的XmlWebApplicationContext,还真的有一个类似的AnnotationConfigWebApplicationContext,跟我们猜想的类名差不多。

剩下的工作就是使用它来编写代码了,然后使用某个方法来把基于Java的配置元数据传进去,一个方法是直接在Eclipse中使用代码补全功能以及Javadoc查看该类是使用哪个方法来设置基于Java的配置元数据的。当然,这样可能会比较费时间。

另一个方法,就是借助万能的某度搜索引擎了,搜索关键字已经很明确了。

在初始化器中进行整合

假设我们将appA应用的Servlet IoC容器修改为使用基于注解和Java的配置元数据。

首先,当然是要编写基于注解和Java的配置元数据,我在原来的config包下新增了一个配置类(参考这篇文章),AppAConfig.java:

package test.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({ "test.appa" })
public class AppAConfig {

}

这个没什么好说的,参考文章已经介绍得很详细了。唯一要关注的是@ComponentScan注解,它其实就类似于基于XML的<component-scan>标记,用来开启该IoC容器的自动扫描和配置,也有一个扫描范围的参数,这个参数是一个字符串数组,即可以传入多个包,用逗号分隔即可。

当然,你也可以在配置类中使用@Bean注解来配置Bean。

然后,就可以在appA的初始化器AppAInitializer中将原来整合基于XML的IoC容器修改为基于注解和Java的IoC容器:

		AnnotationConfigWebApplicationContext appAContext = new AnnotationConfigWebApplicationContext();
		appAContext.register(AppAConfig.class);

可以看到,原来是使用register方法来传入配置元数据的位置,这个位置就是我们编写的配置类,直接使用AppAConfig.class,以后再讨论.class这种用法。

是不是跟整合基于XML的Spring IoC容器很类似,这就是充分利用了举一反三触类旁通的思想。当然,Spring的设计者也是有意这样设计的,因为这样使用者用起来才容易啊,我们也应该尽量把自己的软件设计成这样。

上面整合的是appA的Servlet IoC容器,appB的Servlet IoC容器以及Root IoC容器也是一样的方式。

在web.xml中进行整合

现在假设我们要将appB应用的Servlet IoC容器修改为使用基于注解和Java的配置元数据,但我们不采用初始化器的方式,而是在web.xml中配置appB应用的DispatcherServlet和Servlet IoC容器。

先编写AppBConfig.java:

package test.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({ "test.appb" })
public class AppBConfig {

}

web.xml中原来的appB应用的配置是这样的:

	<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>

是不是只要把<param-value>/WEB-INF/appB-context.xml</param-value>替换成<param-value>test.config.AppBConfig</param-value>就可以了呢?

如果是这样,那DispatcherServlet如何知道使用哪种IoC容器(即WebApplicationContext)呢?除非我们期望Spring MVC的DispatcherServlet足够智能,它能根据contextConfigLocation参数的值判断出是使用基于XML的还是基于注解和Java的配置元数据。

现实可没那么理想,大家可以自己尝试一下,这样修改后会出现错误:

parsing XML document from ServletContext resource [/test.config.AppBConfig];

显然,DispatcherServlet仍然使用的是XmlWebApplicationContext这种基于XML读取配置元数据的IoC容器,我们可以大胆猜想这个是DispatcherServlet的默认值。

那么必然可以向DispatcherServlet传递另外一个指示使用哪种IoC容器的参数,这个参数的值自然是前面我们已经用过的能读取基于注解和Java的配置元数据的IoC容器org.springframework.web.context.support.AnnotationConfigWebApplicationContext,问题就是参数的名字是什么:

	<servlet>
		<servlet-name>appB</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>?????????????</param-name>
			<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
		</init-param>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>test.config.AppBConfig</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

这个参数的名字我是在AnnotationConfigWebApplicationContext的Javadoc中找到的:
基于注解的IoC容器在Spring MVC中的配置.png
所以,以后一定要多看Javadoc。

现在,把?????????????替换成contextClass即可,这样appB的Servlet IoC容器就配置好了,经过验证无误(注意要把原来appB的初始化器去掉)。

剩下的Root IoC容器的配置也可以修改成:

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<context-param>
		<param-name>contextClass</param-name>
		<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
	</context-param>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>test.config.RootConfig</param-value>
	</context-param>

添加一个contextClass的参数,并将contextConfigLocation参数的值改为相应的配置类。

RootConfig.java:

package test.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({ "test.common" })
public class RootConfig {

}

总结

  • 要学会举一反三、触类旁通;
  • 要多看Javadoc。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值