Spring启动加载静态数据时报No Session found for current thread异常

59 篇文章 2 订阅
24 篇文章 0 订阅

一、Spring启动加载静态数据的方法

利用Spring启动加载静态数据,有那么几种方法

1. 实现BeanPostProcessor接口
@Component
public class LoadDataCache implements BeanPostProcessor {

	@@Resource
	private IDao dao;

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// Bean实例化之前执行
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// Bean实例化之后执行
		List list = dao.findAll();
		..... // 做一些事情
		return bean;
	}
}
2. 实现ApplicationListener接口
@Component
public class LoadDataCache implements ApplicationListener<ApplicationEvent> {

	@Resource
	private IDao dao;
	
	@Override
	public void onApplicationEvent(ApplicationEvent arg0) {
		// 在spring所有资源(xml和注解)加载注入完毕后执行
		List list = dao.findAll();
		..... // 做一些事情
	}
}
3. 利用bean便签中的init-method属性
@Component
public class LoadDataCache {

	@Resource
	private IDao dao;
	
	public void init() {
		// 在Bean实例化之前执行
		List list = dao.findAll();
		..... // 做一些事情
	}
}

但是加载静态数据时,如果Dao层获取Hibernate的Session是CurrentSession,那么或许你就会遇到类似No Session found for current thread异常。

之所以产生这个异常,是因为该Dao的执行方法没有纳入事务的管理,可能一些人说,我明明配置了事务呀,配置也看不出什么问题,可为什么还会报异常呢?我也是困惑了好一阵才弄明白。

Spring实现事务的方式是采用Aop技术,既然是Aop,自然离不开代理,可要想代理一个类,该类就必须首先要实例化才行!

仔细看我上面几个例子的注释说明,如果在Bean实例化之前执行Dao层操作就会产生异常。那么上述几种方法中,第三种方法明显存在问题。但我说了第三种方法也是可以实现启动加载的,那么怎么做呢?

二、第三种方法解决方案

1). 另建一个类,Spring配置init-method指向到该类的init方法,在该类的init方法中再执行LoadDataCache类的init方法。其实就相当于建一个包装类封装一下。

2). 注入SessionFactory,开启一个session并绑定到事务里。

@Component
public class LoadDataCache {

	@Resource
	private IDao dao;
	
	@Resource
	private SessionFactory sessionFactory;
	
	public void init() {
		Session session = sessionFactory.openSession();
		TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));

		List list = dao.findAll();
		..... // 做一些事情
	}
}

3). 注入SessionFactory,开启一个session并自己打开事务并执行查询,换句话说,就不用IDao里的方法了。

三、内部方法的相互调用时产生的事务问题

另外,我们习惯将事务管理控制在service层,但如果发生如下情况时:

public interface AService {
	public void a();

	public void b();
}

@Service()
public class AServiceImpl1 implements AService {

	// 或者采用声明式事务一样
	@Transactional(propagation = Propagation.REQUIRED)
	public void a() {
		this.b();
	}

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void b() {
	}
}

 这时同样会发生No Session found for current thread异常,其道理一样是Aop的原因,this.b()是自己直接调用自己内部的一个方法,因而在执行b方法时并不是通过代理去执行的。最简单的解决办法:

在Spring配置文件中配置,开启暴露Aop代理到ThreadLocal的支持

<aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->
<aop:config expose-proxy="true"><!—xml风格支持-->

然后修改this.b()为((AService) AopContext.currentProxy()).b()。

四、AOP原理图

关于AOP知识的详细内容,大家可上网查阅相关资料,我也曾经写过介绍的文章,这里就不再叙述了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值