这两天在修改之前项目中用到的pvuv统计代码 , 遇到了一个问题 , 就是几个项目之间 , 在处理uv的时候 , 都需要特殊的处理 , 区别对待 , 于是我就写了个简单工厂 , 在工厂中初始化不同service的时候 , 想起来平时不用junit测试时 , 就是用的手动读取spring配置的方式来获取容器 , 于是当时想当然地就再次用了这种方法, code如下:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
之后过了一天 , 代码修改完成 , 上测试库测试 , 然后莫名其妙就出现了一个异常 : Dead lock , 而且还是一直不停地死锁 , 仔细检查日志发现是定时任务的问题 , 再一看 , 原来同时有两条线程在跑定时任务 , 这时候我才突然想起来 , 手动加载spring配置文件的话 , 相当于重新加载了一遍所有注入的bean , 于是就有了两个相同的调度在跑了 , 自然就容易出现死锁了 .
于是赶紧去百度google了一把 , 找打了动态获取spring注入的bean , 但是不第二次加载配置的方法 , 方法有好几种 , 比如 :
extends ApplicationObjectSupport
extends WebApplicationObjectSupport
implement ApplicationContextAware
第一种方式 , spring在容器初始化的时候 , 通过方法
void setApplicationContext(ApplicationContext context)
把容器注入, 然后在需要的时候 , 通过以下方法获取容器对象 .
ApplicationContext getApplicationContext()
第二种方法与第一种方式类似 , 不同的是返回的容器类型不一样而已 .
其实观察三个类的源码可以发现 , 其实现方式大同小异 , 前两种方式的父类 , 其实也实现了ApplicationContextAware接口 , 再来看一下ApplicationContextAware的注释 :
Interface to be implemented by any object that wishes to be notified of the {@link ApplicationContext} that it runs in.
Implementing this interface makes sense for example when an object requires access to a set of collaborating beans. Note that configuration via bean references is preferable to implementing this interface just for bean lookup purposes 由注释可见 , 这个接口主要就是为了用来获取注入的bean的 . 我使用的是第三种方法 , 写了一个工具类 , 实现了ApplicationContextAware接口 , 专门用来在非注入的类中获取spring容器 .
public class SpringContextFactory implements ApplicationContextAware{
private static ApplicationContext ctx ;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextFactory.ctx = applicationContext;
}
public static ApplicationContext getApplicationInstance(){
return ctx;
}
}
然后将 SpringContextFactory 注入在spring的配置文件中即可.
<bean id="springContextFactory" class="com.lrlz.statistical.service.factory.SpringContextFactory">bean>
打包 , 发布 , 死锁的问题终于解决了 , 看来spring框架还是有许多值得我们深掘和学习的地方 , 我还是用得太浅薄了 , 是时候该读一波源码加深理解了 .