源代码解读Cas实现单点登出(single sign out)功能实现原理

(2008年07月09日)发表于BlogJava-首页技术区
     摘要: 声明:本博客属作者原创,如果任何网站转载本文,请注明作者及引用来源,谢谢合作! 关于Cas实现单点登入(single sing on)功能的文章在网上介绍的比较多,想必大家多多少少都已经有所了解,在此就不再做具体介绍。如果不清楚的,那只能等我把single sign on这块整理出来后再了解了。当然去cas官方网站也是有很多的文章进行介绍。cas官网http://www.ja-sig.org...   阅读全文

x.matthew 2008-07-09 22:44 发表评论
阅读全文...
本站相关内容:

源代码解读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!



x.matthew 2008-10-11 18:01 发表评论

xwork源代码--Configuration


作者: 1998a  链接: http://1998a.javaeye.com/blog/228577  发表时间: 2008年08月16日

声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!

1.com.opensymphony.xwork2.config.entities.PackageConfig
PackageConfig中Constructor为protected,所有实例的初始化都要通过内部内Builder,例如:

PackageConfig pack = new PackageConfig.Builder("test").build();为何?
Builder的文档为:
/**
     * The builder for this object.  An instance of this object is the only way to

construct a new instance.  The
     * purpose is to enforce the immutability of the object.  The methods are structured in

a way to support chaining.
     * After setting any values you need, call the {@link #build()} method to create the

object.
     */
Build方法如下:
public PackageConfig build() {
            target.actionConfigs = Collections.unmodifiableMap(target.actionConfigs);
            target.globalResultConfigs = Collections.unmodifiableMap

(target.globalResultConfigs);
            target.interceptorConfigs = Collections.unmodifiableMap

(target.interceptorConfigs);
            target.resultTypeConfigs = Collections.unmodifiableMap

(target.resultTypeConfigs);
            target.globalExceptionMappingConfigs = Collections.unmodifiableList

(target.globalExceptionMappingConfigs);
            target.parents = Collections.unmodifiableList(target.parents);

            PackageConfig result = target;
            target = new PackageConfig(result);
            return result;
        }
最后为何在在原来target基础上新new一个PackageConfig呢?
我的想法是这样做的目的是保证PackageConfig是个immutable对象,就是说客户端得到的PackageConfig

对象都是不可变的,所有的可变性操作都是通过PackageConfig.Builder实现的。同样,ActionConfig、

ResultTypeConfig等Config类型对象的immutable也是通过这种方式实现的。

2.com.opensymphony.xwork2.config.Configuration
这个Configuration对象让我想起来Topcoder的ConfigurationAPI组件,一个DTO对象,用于向其他组件

提供对配置文件内容的映射。具体关系如下图:
 
与之不同的是,这里的Configuration还包括了一个reload方法,用于告诉Configuration加载配置文件

。当然,采用了Strategy模式,所有的配置文件读取细节都delegate给ConfigurationProvider,这样一

来便于更改配置文件细节,达到了与核心解耦的目的。

com.opensymphony.xwork2.config.providers.XmlConfigurationProvider便是读取XML配置文件的

provider。

3、com.opensymphony.xwork2.config.ConfigurationManager
这才是configuration最核心的地方。所有上面说到的Configuration或是ConfigurationProvider都被聚

合到ConfigurationManager里,通过getConfiguration这个方法得到Configuration对象。
public synchronized Configuration getConfiguration() {
        if (configuration == null) {
            setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));
            try {
                configuration.reloadContainer(getContainerProviders());
            } catch (ConfigurationException e) {
                setConfiguration(null);
                throw new ConfigurationException("Unable to load configuration.", e);
            }
        } else {
            conditionalReload();
        }

        return configuration;
}


本文的讨论也很精彩,浏览讨论>>


JavaEye推荐



CAS

Canadian 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日)