Spring bean init-method方法中不能有查询数据库的操作吗?
本帖最后由 sunshine_love 于 2013-11-19 16:39:48 编辑 需求大致是这样的:
楼主想在项目启动之后执行一个数据库查询,将需要的数据缓存一下。
下面定义了一个bean,定义了bean初始化之后调用的方法init,在init方法中查询数据库,但却抛出了异常,提示:No Session found for current thread。
疑问是在bean的init-method中不能出现查询数据库的操作吗?
还望大神们能够指点一二,不胜感激:
异常信息:
2013-11-19 16:17:59 [pool-3-thread-1] ERROR - Context initialization failed org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:308)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'moduleCacheService' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: No Session found for current thread
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4779)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5273)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1566)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1556)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:883)
at com.dt5000.homework.dao.BaseDAO.getSession(BaseDAO.java:52)
at com.dt5000.homework.dao.BaseDAO.find(BaseDAO.java:371)
at com.dt5000.authority.service.impl.ModuleCacheServiceImpl.init(ModuleCacheServiceImpl.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1581)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1522)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 22 more
<!-- 配置事务特性,配置add,delete,update开始的方法,事务传播特性为required -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="delete*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="update*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="save*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="edit*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:advisor
pointcut="execution(* com.dt5000.authority.service.impl.*ServiceImpl.*(..))"
advice-ref="txAdvice" />
</aop:config>
<bean id="moduleCacheService" class="com.dt5000.authority.service.impl.ModuleCacheServiceImpl"
scope="singleton" init-method="init" destroy-method="destroy">
</bean>
/**spring
* file name: ModuleCacheService.java
* Author: wangpj
* Create Date: 2013-11-19
* Description:
*
*/
package com.dt5000.authority.service.impl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.transaction.annotation.Transactional;
import com.dt5000.authority.bean.Group;
import com.dt5000.authority.bean.Module;
import com.dt5000.homework.dao.BaseDAO;
public class ModuleCacheServiceImpl {
@Autowired
private EhCacheCacheManager cacheManager;
@Autowired
private BaseDAO baseDAO;
/**
* 类初始化之后调用的方法
*/
@Transactional
@SuppressWarnings("unchecked")
public void init(){
//获取配置文件中的cache
CacheManager ehCacheManager = cacheManager.getCacheManager();
Cache cache = ehCacheManager.getCache("groupModuleCache");
//查询每个组对用的module集合
Group group = null;
List<Module> modules = null;
Map<Integer, List<Module>> groupModuleMap = new HashMap<Integer, List<Module>>();
String queryGroupHql = "from Group order by id";
String queryModuleHql = "select module from GroupModule where group.id=? order by module.id ";
List<Group> groups = baseDAO.find(queryGroupHql);
for (Iterator<Group> iterator = groups.iterator(); iterator.hasNext();) {
group = iterator.next();
modules = baseDAO.find(queryModuleHql, group.getId());
groupModuleMap.put(group.getId(), modules);
}
cache.put(new Element("key", groupModuleMap));
}
/**
* 类销毁之前调用的方法
*/
public void destory(){
}
/**
* @param args
*/
public static void main(String[] args) {
}
}
因此,基本上init-method是没有成功的可能的(多级ApplicationContext,则因为每级会独立完成初始化,属于另一种情况)
一般来讲,依赖别的类初始化完成后执行的代码 是通过 实现 InitialzingBean接口
afterPropertiesSet方法来执行的。
[解决办法]
引发这个错误的表现是Hibernate,实际情况由于Spring托管Bean的生命周期引发的。。。
当你的Bean在创建后,Spring立刻会调用Init用于类的初始化,整个由托管的SpringBean其实并没有完全被初始化完成,类加载顺序的不同会导致系统出现莫名其妙的问题。。
解决办法:
不要使用Init方式初始化,而是监听Spring的上下文事件,接收Refresh事件(全名忘记了),此事件表示Spring完成的上下文的创建,这个时候你所有的bean都加载完成并可以提供工作了,这个时候你可以随意操作数据库了
[解决办法]
事件监听也是可以。
就是代码多一点罢了。