spring在web容器启动时执行初始化方法
2015-09-29 00:00
627 查看
需求:在tomcat启动时开启一个定时任务。
想法:容器启动时执行方法,最容易想到的就是servlet中可以配置load-on-startup,设置一个正整数也就可以随容器一起启动。
问题:上面的方法很好,但是由于定时任务需要去操作数据库,而项目采用了spring的依赖注入来管理对象,而servlet并不受Spring的管理。若此时在servlet中注入Spring管理的对象,则会报错:javax.naming.NameNotFoundException: Name com.test.InitServlet is not bound in this Context。
所以想要再servlet中操作数据库,只能手动去创建一个service,这显然违背了我们使用Spring的初衷,让项目看起来不伦不类的。那么如何才能在启动WEB容器的时候执行一段初始化代码,并且可以让其被Spring管理呢?
解决方案:Spring提供了当一个Bean初始化后执行方法的扩展点:InitializingBean。这里的初始化指的就是当该Bean的属性被注入完成后(注意:这里并不是所有属性都需要被设置),所以InitializingBean接口提供的方法名称也很形象:afterPropertiesSet()。
使用的时,将该Bean注入到Spring容器,之后我们便可以获得Spring容器中的对象了,也就是说,可以得到service方法来执行我们的定时任务了。
具体代码如下:
[java]
view plain
copy
@Component
public class InitServlet implements InitializingBean {
/**
*
*/
private static final long serialVersionUID = 1L;
@Resource
private DispatchesService dispatchesService;
@Override
public void afterPropertiesSet() throws Exception {
<span style="white-space:pre"> </span>dispatchesService.spyDDetails();
}
}
另外还有两种方法也可以实现如上的功能。
1、若采用XML来配置Bean的话,可以指定属性init-method
2、通过注解@PostConstruct来修改初始化方法
值得注意的是,三者可以同时存在,触发的顺序是先触发@PostConstruct修饰的方法,再触发afterPropertiesSet(),最后触发init-method
其中@PostConstruct是通过注册一个BeanPostProcessor,在Bean的初始化方法之前调用,而afterPropertiesSet()和init-method都在初始化方法中调用
关于@PostConstruct详细的介绍可以看这里:http://blog.csdn.net/yaerfeng/article/details/8447530
下面是Spring中调用Bean的初始化代码的源代码:
[java]
view plain
copy
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">// 这里触发afterPropertiesSet</span><span style="white-space:pre">
</span>
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();<span style="white-space:pre"> </span>// 这里触发afterPropertiesSet
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();// 这里是触发init-method
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
补充:
还有一种方法,是当Spring将所有的Bean都初始化完成后,会留给我们一个入口,我们可以实现如下接口
[java]
view plain
copy
@Component
public class InstantiationTracingBeanPostProcessor implements
ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
System.out.println("-----所有Bean载入完成---");
}
}
想法:容器启动时执行方法,最容易想到的就是servlet中可以配置load-on-startup,设置一个正整数也就可以随容器一起启动。
问题:上面的方法很好,但是由于定时任务需要去操作数据库,而项目采用了spring的依赖注入来管理对象,而servlet并不受Spring的管理。若此时在servlet中注入Spring管理的对象,则会报错:javax.naming.NameNotFoundException: Name com.test.InitServlet is not bound in this Context。
所以想要再servlet中操作数据库,只能手动去创建一个service,这显然违背了我们使用Spring的初衷,让项目看起来不伦不类的。那么如何才能在启动WEB容器的时候执行一段初始化代码,并且可以让其被Spring管理呢?
解决方案:Spring提供了当一个Bean初始化后执行方法的扩展点:InitializingBean。这里的初始化指的就是当该Bean的属性被注入完成后(注意:这里并不是所有属性都需要被设置),所以InitializingBean接口提供的方法名称也很形象:afterPropertiesSet()。
使用的时,将该Bean注入到Spring容器,之后我们便可以获得Spring容器中的对象了,也就是说,可以得到service方法来执行我们的定时任务了。
具体代码如下:
[java]
view plain
copy
@Component
public class InitServlet implements InitializingBean {
/**
*
*/
private static final long serialVersionUID = 1L;
@Resource
private DispatchesService dispatchesService;
@Override
public void afterPropertiesSet() throws Exception {
<span style="white-space:pre"> </span>dispatchesService.spyDDetails();
}
}
另外还有两种方法也可以实现如上的功能。
1、若采用XML来配置Bean的话,可以指定属性init-method
2、通过注解@PostConstruct来修改初始化方法
值得注意的是,三者可以同时存在,触发的顺序是先触发@PostConstruct修饰的方法,再触发afterPropertiesSet(),最后触发init-method
其中@PostConstruct是通过注册一个BeanPostProcessor,在Bean的初始化方法之前调用,而afterPropertiesSet()和init-method都在初始化方法中调用
关于@PostConstruct详细的介绍可以看这里:http://blog.csdn.net/yaerfeng/article/details/8447530
下面是Spring中调用Bean的初始化代码的源代码:
[java]
view plain
copy
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">// 这里触发afterPropertiesSet</span><span style="white-space:pre">
</span>
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();<span style="white-space:pre"> </span>// 这里触发afterPropertiesSet
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();// 这里是触发init-method
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
补充:
还有一种方法,是当Spring将所有的Bean都初始化完成后,会留给我们一个入口,我们可以实现如下接口
[java]
view plain
copy
@Component
public class InstantiationTracingBeanPostProcessor implements
ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
System.out.println("-----所有Bean载入完成---");
}
}
相关文章推荐
- 分布式调度QUARTZ+SPRING
- MyEclipse画UML用例图并生成JAVA代码(图文详细步骤)
- eclipse内存溢出报错:java.lang.OutOfMemoryError:Java heap space.
- 细谈Struts2框架(二)Struts2框架之Scope属性
- Java程序,猜大小游戏
- 国内国外最好的java开发论坛及站点[转]
- Date类
- javabean规范中要求实现Serializable接口,有什么作用?
- Java 文件操作
- netbeans中的小知识
- 递归
- java异常基础知识
- spring mvc 接收 put参数
- java去除重复的字符串和移除不想要的字符串
- struts2上传文件的小例子
- Java对象池技术的原理及其实现
- java设计模式第16弹--访问者模式
- java 线程中yield的用法
- java join的用法
- java集合框架小练习