集成 Junit:
示例:
(1)导入相关依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
<scope>test</scope>
</dependency>
需要注意的是,spring-test 的版本要与之前引入的 spring-context 版本一致
(2)创建测试类 SpringJunitTest
import Service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringJunitTest {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.say();
}
}
@RunWith(SpringJUnit4ClassRunner.class) 用于让测试在 Spring 容器环境下执行
@ContextConfiguration 用于指定 xml 配置文件或配置类,如下
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@ContextConfiguration(classes = SpringConfiguration.class)
分析:
Spring 集成 Junit 后,可以通过如上方式进行单元测试,程序自动创建 Spring 容器,我们只需要通过 @Autowired 注解,注入需要测试的 bean 即可
集成 Web 环境:
示例:
(1)创建 Web 层,编写 UserServlet 类
package Web;
import Config.SpringConfiguration;
import Service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = app.getBean(UserService.class);
userService.say();
}
}
重写 doGet 方法,内容为创建 Spring 容器并取得 Service 层对象 userService,调用其 say 方法
(2)在 web.xml 中配置 servlet 映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>Web.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
</web-app>
将访问路径与对应的 servlet 进行映射
(3)在浏览器中访问 localhost:8080/userService 进行测试
启动 Tomcat ,浏览器中访问 localhost:8080/userService
控制台成功输出结果
弊端分析:
当 Web 层的接口较多时,每个 servlet 的处理方法中都需要创建 Spring 容器,导致配置文件/类被加载多次,Spring 容器也被创建多次,影响性能
解决方案:
在 Web 项目中,使用 ServletContextListener 监听 Web 应用的启动,在 Web 应用启动时创建 ApplicationContext 对象,并将其存入 servletContext 域中,便于在任意位置取用 ApplicationContext 对象
(1)创建监听器 ContextLoaderListener
package Listener;
import Config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
sce.getServletContext().setAttribute("app", app);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
监听器类实现 ServletContextListener 接口,并重写 contextInitialized 方法,该方法在 Web 应用启动时会被调用,方法中创建 Spring 容器,并存入 servletContext 域中
(2)在 web.xml 中配置监听器
<listener>
<listener-class>Listener.ContextLoaderListener</listener-class>
</listener>
(3)在 UserServlet 类的 doGet 方法中通过 servletContext 域获取 ApplicationContext 对象
package Web;
import Service.UserService;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
UserService userService = app.getBean(UserService.class);
userService.say();
}
}
对于 ServletContext 对象的获取,有如下两种方式
ServletContext servletContext = req.getServletContext();
ServletContext servletContext = this.getServletContext();
配置文件解耦:
对于监听器中的 ApplicationContext 的创建,需指定配置文件,可以在 web.xml 中配置全局参数,并将配置文件指定为该全局参数,实现配置文件解耦
(1)在 web.xml 中配置全局参数
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
(2)在监听器中取得参数,创建 ApplicationContext 对象
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
ApplicationContext app = new ClassPathXmlApplicationContext(contextConfigLocation);
sce.getServletContext().setAttribute("app", app);
}
通过 ServletContext 对象的 getInitParameter 方法可以获取全局参数
取用 ApplicationContext 优化
(1)编写工具类 WebApplicationContextUtils
package Util;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
public class WebApplicationContextUtils {
public static ApplicationContext getWebApplicationContext(ServletContext servletContext) {
return (ApplicationContext) servletContext.getAttribute("app");
}
}
其中对于静态方法 getWebApplicationContext ,只需传入 ServletContext ,即可返回 ApplicationContext 对象
(2)修改 doGet 方法中对 ApplicationContext 的取用
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.say();
}
直接调用 WebApplicationContextUtils 的静态方法获取 ApplicationContext 对象即可
使用 Spring 工具进行 ApplicationContext 对象的获取:
对于上文中创建的 ContextLoaderListener 、WebApplicationContextUtils ,Spring 提供了完全相同的功能,并封装在了 spring-web 包中
(1)导入相关依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
注意 Spring-web 的版本需要与先前导入的别的 Spring 包的版本相同
(2)在 web.xml 中配置监听器和配置文件全局参数
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
这里的配置文件路径需要加 classpath
(3)使用 WebApplicationContextUtils 获取 ApplicationContext 对象
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.say();
}