在Web工程中配置Spring
要想在Web工程中配置Spring,首先需要在工程加入spring-web包,我这里使用的是maven的web工程,pom.xml配置文件配置的依赖如下:
org.springframework
spring-context
4.3.14.RELEASE
org.springframework
spring-web
4.3.14.RELEASE
javax
javaee-api
7.0
provided
junit
junit
4.0
test
c3p0
c3p0
0.9.1.2
mysql
mysql-connector-java
5.1.44
然后在工程的web.xml文件中配置Spring的监听器,web.xml内容如下:
Archetype Created Web Application
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:app.xml
这里的配置要说明一下,在配置Spring配置文件的路径时,如果你的配置文件放在WEB-INF下是不需要加上 classpath: 前缀的,只需要写上路径即可,例如:
contextConfigLocation
WEB-INF/app.xml
完成以上的配置之后,我们先来写一个简单的Servlet,并配置上Spring的注解:
package org.zero01.test;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component("login")
@WebServlet("/login")
public class LoginServlet extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
然后写一个测试的Servlet,看看能否从Spring容器中获得实例对象,在web项目中我们可以通过WebApplicationContextUtils类来帮我们获取Spring的管理对象:
package org.zero01.test;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.zero01.pojo.Student;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/test")
public class TestServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 获得web工程中的Spring管理对象
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
// 同样的我们可以通过这个管理对象来获得我们需要的实例对象
LoginServlet loginServlet = (LoginServlet) webApplicationContext.getBean("login");
Student student = (Student) webApplicationContext.getBean("stu");
// 先打印一下,看看能否获取到对象
PrintWriter printWriter = resp.getWriter();
printWriter.println(loginServlet);
printWriter.println(student);
}
}
输出结果如下:
org.zero01.test.LoginServlet@5afad74f
org.zero01.pojo.Student@1ff85274
如上,可以看到对象已经成功获取到了,那就代表我们的配置没有问题,这样我们就可以在web项目中愉快的使用Spring了。
简单说明一下WebApplicationContext对象的加载流程:
-
我们都知道Tomcat启动时会去加载web.xml文件中的配置,而我们在web.xml配置了Spring的监听类以及Spring配置文件的路径
- 然后Spring的ContextLoaderListener监听类会监听着ServletContext的初始化以及销毁,这一点查看源码即可得知:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
- 当ServletContext初始化时会调用该监听类的contextInitialized方法,而该方法调用了initWebApplicationContext方法并传递了ServletContext对象,从方法名的字面意思也可以看出这个方法是用于初始化WebApplicationContext对象的
- 当WebApplicationContext被初始化时,通过ServletContext对象得到了我们在web.xml中配置的初始化参数,也就是Spring配置文件的路径,于是Spring的配置文件也被加载起来了,成功加载后,WebApplicationContext对象也就初始化完成了。如果没被加载起来就会报错,初始化失败
- WebApplicationContext对象初始化完成后,就会存放在ServletContext的属性里,这里就完成了整个加载流程
- 但是由于我们不知道键/值是什么,所以我们无法直接在ServletContext里获得WebApplicationContext对象,而是得通过Spring提供的工具类WebApplicationContextUtils来获得
多个Spring配置文件
有些情况下,我们可能需要多个配置文件,每个配置文件配置不同的模块,如下:
当需要将这些配置文件都引入一个总的配置文件时,可以使用以下语句:
Spring配置属性文件
Spring支持使用属性文件来配置一些参数,但是这种使用属性文件来配置参数的方式用得不多,因为很鸡肋,而且还会导致到处都是属性文件的散乱情况。不过有可能在一些特殊的情况下会用到,所以在此也记录一下,这里通过配置数据源对象的参数来演示一下如何通过Spring配置属性文件:
首先创建一个属性文件dataSourceInfo.properties,文件内容如下:
database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql:///school
database.user=root
database.pw=your_password
database.max.pool.size=10
database.min.pool.size=1
database.loginTimeout=2000
然后编辑Spring的配置内容如下:
datasourceinfo.properties
测试代码如下:
package org.zero01.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("app.xml");
DataSource dataSource = (DataSource) app.getBean("dataSource");
try {
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
打印结果:
com.mchange.v2.c3p0.impl.NewProxyConnection@3578436e
从打印结果可以看到,数据源对象已经成功拿出来了。但是从整个配置流程可以看到有了Spring后还使用属性文件来配置参数就有些绕弯子了,这些参数都是可以在Spring配置文件中直接配置的,而且本身Spring的目的之一就是避免存在大量的属性文件。
Spring在web项目中的初始化类
如果你希望在Tomcat服务器启动时,初始化一个类,并调用该类中的某个方法时,那么你就可以通过实现Spring中的两个接口来完成。首先是InitializingBean接口,实现这个接口的类会在Tomcat服务器启动时被初始化并调用其中的afterPropertiesSet方法:
package org.zero01.test;
import org.springframework.beans.factory.InitializingBean;
public class InitBean implements InitializingBean {
public void afterPropertiesSet() throws Exception {
System.out.println("我被初始化了 —— InitializingBean");
}
}
另一个接口是 ApplicationListener ,这个接口的方法有数据源参数,所以这个方法可以完成更多的事情,而且当你有某个逻辑是必须要等到所有的bean都被处理完成之后再执行的话,就适合使用这个接口,因为所有的bean都被处理完成之后这个接口的方法才会被调用:
package org.zero01.test;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class AppInit implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("我被初始化了 —— ApplicationListener");
}
}
然后需要配置一下这两个类,Spring配置文件内容如下:
完成配置后启动Tomcat服务器,Tomcat服务器启动时输出结果如下:
可以看到,实现 InitializingBean 接口的类比实现 ApplicationListener 接口的类先被初始化。所以它们之间还是有一些区别的,需要根据具体的业务场景来进行使用哪一个接口。
通过实现接口获得ApplicationContext或者BeanFacrory的对象
通过实现接口获得ApplicationContext对象,代码如下:
package org.zero01.test;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class Test implements ApplicationContextAware {
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
LoginServlet loginServlet = (LoginServlet) applicationContext.getBean("login");
}
}
通过实现接口获得BeanFacrory对象,代码如下:
package org.zero01.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class Test implements BeanFactoryAware {
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
LoginServlet loginServlet = (LoginServlet) beanFactory.getBean("login");
}
}