Spring整合web环境
# 1、Javaweb三大组件及环境特点
在Java语言范畴内,web层框架都是基于Javaweb基础组件完成的,所以有必要复习一下Javaweb组件的特点
| 组件 | 作用 | 特点 |
|---|---|---|
| Servlet | 服务端小程序,负责接收客户端请求并作出响应 | 单例对象,默认在第一次访问时创建(可配置为服务器启动时创建)。创建后执行 init 方法;每次请求都会执行 service 方法。一个业务功能对应一个 Servlet,配置繁琐。 |
| Filter | 过滤器,负责对客户端请求进行过滤操作 | 单例对象,服务器启动时创建。对象创建后执行 init 方法;每次请求通过过滤器链时执行 doFilter 方法,用于放行或拦截请求。 |
| Listener | 监听器,监听域对象的创建和属性变化 | 可监听域对象的创建/销毁,也可监听属性变化。按监听的范围可分为监听 Request、Session 和 ServletContext 域。 |
# 2、Spring整合web环境的思路及实现
在进行Java开发时要遵循三层架构+MVC,Spring操作最核心的就是Spring容器,web层需要注入Service,service层需要注入Dao(Mapper),web层使用Servlet技术充当的话,需要在Servlet中获得Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationContextConfig.class);
AccountService accountService = (AccountService)applicationContext.getBean("accountService");
accountService.transferMoney("tom","lucy",100);
web层代码如果都去编写创建AnnotationConfigApplicationContext的代码,那么配置类重复被加载了,Spring容器也重复被创建了,不能每次想从容器中获得一个Bean都得先创建一次容器,这样肯定是不允许。
所以,我们现在的诉求很简单,如下:
ApplicationContext创建一次,配置类加载一次;
最好web服务器启动时,就执行第1步操作,后续直接从容器中获取Bean使用即可;
ApplicationContext的引用需要在web层任何位置都可以获取到。
针对以上诉求我们给出解决思路,如下:
在ServletContextListener的contextInitialized方法中执行ApplicationContext的创建。或在Servlet的init方法中执行ApplicationContext的创建,并给Servlet的load-on-startup属性一个数字值,确保服务器启动Servlet就创建;
将创建好的ApplicationContext存储到ServletContext域中,这样整个web层任何位置就都可以获取到了
自定义代码完成上述ContextLoaderListener和WebApplicationContextUtils(见代码)
# 3、Spring的web开发组件spring-web
到此,就将一开始的诉求都解决了,当然我们能想到的Spring 框架自然也会想到,Spring其实已经为我们定义好了一个ContextLoaderListener,使用方式跟我们上面自己定义的大体一样,但是功能要比我们强百倍,所以,遵循Spring "拿来主义" 的精神,我们直接使用Spring提供的就可以了,开发如下:
先导入Spring-web的坐标:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.7</version>
</dependency>
在web.xml中去配置ContextLoaderListener,并指定配置文件的位置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
在Servlet中直接使用
@WebServlet("/accountServlet")
public class AccountServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 获取 ServletContext
ServletContext servletContext = request.getServletContext();
// 2. 从 ServletContext 中获取 Spring 容器(ApplicationContext)
ApplicationContext applicationContext =
WebApplicationContextUtils.getWebApplicationContext(servletContext);
// 3. 获取 AccountService Bean
AccountService accountService = applicationContext.getBean(AccountService.class);
// 4. 调用业务逻辑方法
accountService.transferMoney("tom", "lucy", 500);
}
}
如果核心配置类使用的是注解形式的,那么Spring容器是AnnotationConfigWebApplicationContext,如下配置方式
public class MyAnnotationConfigWebApplicationContext extends AnnotationConfigWebApplicationContext {
public MyAnnotationConfigWebApplicationContext() {
// 注册核心配置类
super.register(ApplicationContextConfig.class);
}
}
<context-param>
<param-name>contextClass</param-name>
<param-value>com.itheima.web.MyAnnotationConfigWebApplicationContext</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>