上篇文章说到了在tomcat启动后如何进行系统的初始化工作:
想看的可点击—— tomcat启动后进行系统初始化及系统销毁执行业务
关于Spring容器初始化及获取实例,就要用到2个容器了:
一个是ServletContext,一个是WebApplicationContext。
ServletContext是servlet容器。用于获取web.xml中配置的参数,或者其他用户。
WebApplicationContext是spring的核心,是spring中的存放bean的容器。
说到初始化容器及获取实例,就要用到WebApplicationContextUtils这个工具类,
WebApplicationContextUtils是一个抽象类,其提供了一个很便利的方法来获取spring应用的上下文即WebApplicationContext。
其中的静态方法getWebApplicationContext(ServletContext sc),提供一个ServletContext 类型参数即可。
其原理十分简单,在spring容器初始化的方法
org.springframework.web.context.ContextLoader.initWebApplicationContext(ServletContext)
中通过servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);已经将WebApplicationContext的实例放入ServletContext 中了。
然后在工具类的
org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(ServletContext)
中就可以通过传入的ServletContext参数获取到WebApplicationContext实例了。
看一下代码
import javax.servlet.ServletContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* spring
*/
public class SpringContext {
private final static Logger logger = LoggerFactory.getLogger(SpringContext.class);
private static ServletContext context;
private static WebApplicationContext appContext;
/**
* 初始化Spring容器(需在web起动时就初始化)
* @param sc
*/
public synchronized static void initContext(ServletContext sc){
if(appContext == null){
context = sc;
appContext = WebApplicationContextUtils.getWebApplicationContext(sc,"org.springframework.web.servlet.FrameworkServlet.CONTEXT.springServlet");
}
}
/**
* 返回容器 环境上下文
* @return
*/
public static ServletContext getContext(){
return context;
}
/**
* 返回Spring容器 环境上下文
* @return
*/
public static WebApplicationContext getAppContext(){
return appContext;
}
/**
* 根据类返回实例.
* <BR> 不建议使用。如果当前类有多个实现则无法定位到具体使用哪个实现类
* @param name
* @return
*/
public static <T> T getBean(Class<T> t){
Assert.notNull(appContext);
return (T)appContext.getBean(t);
}
/**
* 根据发布名称返回实例.
* @param name
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name){
Assert.notNull(name);
return (T)appContext.getBean(name);
}
/**
* 根据发布名称返回实例.
* @param name
* @return
*/
public static boolean containsBean(String name){
Assert.notNull(name);
return appContext.containsBean(name);
}
/**
* 根据类全称返回实例.
* @param name
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getBeanByClassName(String name){
Assert.notNull(name);
try {
Class<?> cls=Class.forName(name);
return (T)appContext.getBean(cls);
} catch (ClassNotFoundException e) {
logger.error("根据类全称返回实例失败,找不到类:"+name,e);
return null;
}
}
}
这里呢,我们不光获取了Spring容器的实例,还对该实例进行了一下方法扩展,因为Bean在Spring的管理下都是单例的,所以最好的办法就是用这些方法去Spring容器中获取Bean,
然后就用到了上篇文章的初始化方法了, 在初始化方法中执行initContext就行了,该方法加synchronized关键字是防止初始化多次
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 所有初始化工作
* @author Run the ant
* @date 2018-08-17
* @version 1.0
*/
public class InitServlet extends HttpServlet {
private static final long serialVersionUID = 3117103275293498582L;
private Logger logger = LoggerFactory.getLogger(InitServlet.class);
public void init(ServletConfig config) throws ServletException {
logger.info("InitServlet init start");
long start = System.currentTimeMillis();
//初始化SpringContext容器
SpringContext.initContext(config.getServletContext());
//下面这行不要忘了,执行这行才能生效!!!
super.init(config);
logger.info("InitServlet init completed in {}ms",(System.currentTimeMillis()-start));
}
public void destroy() {
logger.info("InitServlet destroy.....");
//在这里进行所有的销毁工作!!!
super.destroy();
}
}
好啦~~~~
其实还可以再改进一下,比如如果需要初始化的内容过多,不方便在该方法写,可以扩展一个类,或者接口等,用工厂模式,至于如何扩展,扩展到什么地步就看你自己啦,
为什么这样说呢,因为
SpringContext.initContext(config.getServletContext());
执行完之后,Spring的容器实例我们获取到了,并且已经有了各种获取Bean的方法了,我们完全可以根据这些方法,来获取某个初始化工厂的实例,然后执行初始化方法
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 所有初始化工作
* @author Run the ant
* @date 2018-08-17
* @version 1.0
*/
public class InitServlet extends HttpServlet {
private static final long serialVersionUID = 3117103275293498582L;
private Logger logger = LoggerFactory.getLogger(InitServlet.class);
//下面就是我的初始化工厂,该工厂有2个方法,一个init方法,一个destroy方法,
private InitConfigFactory configFacroty;
public void init(ServletConfig config) throws ServletException {
logger.info("InitServlet init start");
long start = System.currentTimeMillis();
//初始化SpringContext容器
SpringContext.initContext(config.getServletContext());
//系统初始化,用我们之前初始化Spring容器写的方法获取到实例,执行就行了
configFacroty = SpringContext.getBean(InitConfigFactory.class);
configFacroty.init(config);
//下面这行不要忘了,执行这行才能生效!!!
super.init(config);
logger.info("InitServlet init completed in {}ms",(System.currentTimeMillis()-start));
}
public void destroy() {
logger.info("InitServlet destroy.....");
//系统销毁,用工厂的销毁方法
configFacroty.destroy();
super.destroy();
}
}
所有的你能想到的扩展,都可以在InitConfigFactory工厂类中做文章了,JAVA的多态,尽情施展吧~~~
如果你还是不会扩展,等我下篇博文。。。。