源代码解读Cas实现单点登出(single sign out)功能实现原理 |
(2008年07月09日)发表于BlogJava-首页技术区 |
| 阅读全文... |
本站相关内容: |
|
源代码解读Spring+Hibernate(JPA)的LazyLoadException异常好久的笔记了,趁刚好休息整理文档,翻出这一部分,稍加整理后,就发上来给大家共享一下,希望对各位有所帮助。 关于LazyLoadException异常,使用过Hibernate O/R Mapping工具的人应该都遇到过,网上也是有很多解决的方案,其中Spring提供的一个方案就是在web.xml增加一个filter,示例代码如下: <filter>
<filter-name>entityManager</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>entityManagerFilter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> 解决办法有了,接下来应该会有人好奇:这个配置filter后它是如何工作的? 下面来分析一下这个功能实现的源代码, 不过之前,比较重要的是了解,为何会出现lazyload exception的异常发生。 下面我模拟写了一段代码,这段代码就会发生该异常 注:只是为了说明,相关的代码就省略了。 @Entity
public class Room { @Id @Column(length=32) private String id; @Column(length=20) private code; @OneToMany(mappedBy="room") //default is use lazy load strategy private Set desks; } @Entity public class Desk { @Id @Column(length=32) private String id; @Column(length=20) private code; @ManyToOne private Room root; } public class RoomSerivce { @Transactional(readOnly=true) public Room getRoomById(String roomId) { Assert.notBlank(roomId, "room'id is null); return getDao().findById(roomId); } } 1 public class RoomServiceTest {
2 3 public static void main(String[] args[]) { 4 5 //get service from spring beanfactory 6 RoomService service = SpringContext.getSerivce("roomService"); 7 Assert.notNull(service, " roomService bean not exsit"); 8 9 Room room = service.getRoomById("1"); 10 //here lazy exception throw out 11 Set Desks = room.getDesks(); 12 CollectionsUtils.toString(Desks); 13 } 14 } 分析这段代码,我们不难发现,在RoomServiceTest这个测试的例子中,因为使用了基于Annotation的声明性事务,所以在RoomSerivce.getRoomById方法运行结束后,事务就已经提交了。但示例中Room实体与Desk实例的关系使用的是lazy fetch的策略,此时Room对象中的desks集合还是为空。 当执行到下面两句时(这才真正使用到desks集合时) Set Desks = room.getDesks(); CollectionsUtils.toString(Desks); Hibernate就会根据原来lazy设定的方式,取EntityManager, 根据它从数据库查询 Desk实现的数据,这时上面我们已经提到,事务已经随getRoomById方法的运行结束提交. EntityManager对象也已经关闭。此时再调用 EntityManager操作,就会报EntityManager has been closed 异常(lazy load exception) ok, 清楚这块,大家有时可能也猜想到了Spring这个解决方案是怎么处理的了。 Spring的TransactionInterceptor 其就是通过AOP负责拦截着所有针对事务TransactionManager的操作. 这样Spring就可以针对lazy异常进行拦截了。 清楚上面的后,下面的代码是非常好理解了,来看一下OpenEntityManagerInViewFilter的代码: 我加了些注释,大家很容易明白: 1 protected void doFilterInternal(
2 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 3 throws ServletException, IOException { 4 5 //通过WebApplicationContext,从Web服务中取得context实例后,根据EntityManagerFactory.class类型 6 //取得EntityManagerFacotry实例 7 EntityManagerFactory emf = lookupEntityManagerFactory(request); 8 boolean participate = false; 9 10 //如果静态方法hasResource已经有EntityManagerFactory实例了,就不用再通过 11 //EntityManagerFactory创建一个新EntityManger了 12 if (TransactionSynchronizationManager.hasResource(emf)) { 13 // Do not modify the EntityManager: just set the participate flag. 14 participate = true; 15 } 16 else { 17 logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewFilter"); 18 try { 19 //通过EntityManagerFactory创建一个新EntityManger,并通过bindResource方法 20 //保存到TransactionSynchronizationManager中 21 //这样,通TransactionSynchronizationManager的getResource方法取得EntityMangerHolder 22 EntityManager em = createEntityManager(emf); 23 TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em)); 24 } 25 catch (PersistenceException ex) { 26 throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex); 27 } 28 } 29 30 try { 31 filterChain.doFilter(request, response); 32 } 33 34 finally { 35 if (!participate) { 36 //每次请求结束后,就把EntityManager关闭 37 EntityManagerHolder emHolder = (EntityManagerHolder) 38 TransactionSynchronizationManager.unbindResource(emf); 39 logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter"); 40 EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager()); 41 } 42 } 43 } 44 上面的代码就不用多解释了, 到现在已经很清楚知道Spring针对 Hibernate的Lazy问题是怎么解决的。 当然我们可以扩展到除Web服务以外,来实现解决lazy的问题。(我们自己来管理TransactionSynchronizationManager就可以了) 当然Spring针对 Hibernate(非JPA的实现)原理也是一样,只是它针对的SessionFactory,也是由TransactionSynchronizationManager来统一管理。 最后如果大家如还有不清楚的,欢迎一起讨论。 Good Luck! Yours Matthew!
xwork源代码--Configuration作者: 1998a 链接: http://1998a.javaeye.com/blog/228577 发表时间: 2008年08月16日 声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任! 1.com.opensymphony.xwork2.config.entities.PackageConfig 本文的讨论也很精彩,浏览讨论>> JavaEye推荐
CASCanadian Mind Products | Java Glossary (26 reads) CAS is Central Authetication Service, a Java-based protocol developed at Yale for entrprise-wide authentication of users by applications.
mysql源代码安装mysql源代码安装方法
java 源代码地址http://www.chinaitlab.com/www/school/codesearch/ http://www.cn-java.com/index ... java 绘图 |
互联网相关内容: |
| 源代码解读Spring+Hibernate(JPA)的LazyLoadException异常 (2008年10月11日) |
| xwork源代码--Configuration (2008年08月16日) |
| CAS (2008年08月21日) |
| mysql源代码安装 (2007年09月16日) |
| java 源代码地址 (2007年09月25日) |
| 开放源代码 - Wikipedia (2007年09月26日) |
| .NET FX库源代码 (2007年10月05日) |
| Sandcastle源代码已发布 (2008年07月04日) |
| 看grok的源代码 (2008年10月08日) |




