【总结-含源代码】Spring Security学习总结一 |
(2008年08月20日)发表于BlogJava-首页技术区 |
|
Hibernating 2008-08-20 10:25 发表评论
|
| 阅读全文... |
本站相关内容: |
|
源代码解读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!
Spring配置总结作者: robustwang 链接: http://robustwang.javaeye.com/blog/210678 发表时间: 2008年07月02日 声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任! web.xml 载入Log4j配置 <context-param><!--Log4j配置 在同一容器中部署多个应用不能使用默认的webAppRootKey,必须指定唯一KEY,以免冲突--> <param-name>webAppRootKey</param-name> <param-value>itservice.root</param-value> <!--在log4j.properties中设置日志路径log4j.appender.file.File=${itservice.root}/WEB-INF/itservice.log--> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/classes/log4j.properties</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> 载入Spring配置文件 <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/applicationContext.xml</param-value> <!--可载入多个配置文件分隔符 , ; \t \n --> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 字符编码过滤器 <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> 配置延迟加载时使用OpenSessionInView <filter> <filter-name>openSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> <init-param> <param-name>singleSession</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>sessionFactoryBeanName</param-name> <!--指定对Spring配置中哪个sessionFactory使用OpenSessionInView--> <param-value>sessionFactory_itdb</param-value> </init-param> </filter> <filter-name>openSessionInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> Struts-config.xml <action input="/index.jsp" name="loginActionForm" parameter="method" path="/loginAction" scope="session" type="org.springframework.web.struts.DelegatingActionProxy" validate="true" /> <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/classes/action-servlet.xml" /> <!--将spring配置中关于ACTION的配置独立到一个action-servlet.xml文件中--> </plug-in> ApplicationContext.xml <!--直接使用hibernate配置文件--> <bean id="sessionFactory_itdb" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation"> <value>classpath:hibernate_itdb.cfg.xml</value> </property> </bean> <!--使用JNDI DataSource--> <bean id="it_dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jdbc/itdb</value> </property> </bean> <!-- Spring配置DataSource --> <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>classpath:init.properties</value> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${dataSource.driverClassName}"></property> <property name="url" value="${dataSource.url}"></property> <property name="username" value="${dataSource.username}"></property> <property name="password" value="${dataSource.password}"></property> </bean> <!-- *********************Hibernate*********************** --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="mappingResources"> <list> <value>com/usish/shweb/hbm/ShwebFile.hbm.xml</value> <value>com/usish/shweb/hbm/ShwebLog.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.jdbc.fetch_size">50</prop> <prop key="hibernate.jdbc.batch_size">30</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> </bean> <!--******************TransactionManager***********************--> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory" /> </property> </bean> <bean id="baseTxProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true" abstract="true"> <property name="transactionManager"> <ref bean="transactionManager" /> </property> <property name="transactionAttributes"> <props> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="get*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="delete*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!--AOP TX--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" propagation="NEVER"/> <tx:method name="find*" propagation="NEVER"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="txBusinessMethods" expression="execution(* com.ztgame.blog.business.*BusinessImpl.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txBusinessMethods"/> </aop:config> <!--annotation TX--> <tx:annotation-driven proxy-target-class="true" transaction-manager="txManager"/> Spring编程式事物 <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref bean="TransactionManager"/> </property> </bean> <bean id="courseService" class="com.test.CourseService"> <property name="transactionTemplate"> <ref bean="transactionTemplate"/> </property> </bean> private TransactionTemplate transactionTemplate; public void enrollStudent()...{ transactionTemplate.execute(new TransactionCallback()...{ public Object doInTransaction(TransactionStatus ts)...{ try ...{ // 需要事务控制的方法代码 } catch (Exception e) ...{ ts.setRollbackOnly(); //回滚 } return null; //事务提交 } }); } } 7个事务策略: 1、 PROPAGATION_REQUIRED -- 支持当前的事务,如果不存在就创建一个新的。这是最常用的选择。 2 、 PROPAGATION_SUPPORTS -- 支持当前的事务,如果不存在就不使用事务。 3 、 PROPAGATION_MANDATORY -- 支持当前的事务,如果不存在就抛出异常。 4 、 PROPAGATION_REQUIRES_NEW -- 创建一个新的事务,并暂停当前的事务(如果存在)。 5 、 PROPAGATION_NOT_SUPPORTED -- 不使用事务,并暂停当前的事务(如果存在)。 6 、 PROPAGATION_NEVER -- 不使用事务,如果当前存在事务就抛出异常。 7 、 PROPAGATION_NESTED -- 如果当前存在事务就作为嵌入事务执行,否则与 PROPAGATION_REQUIRED 类似。 5个隔离策略: ISOLATION_DEFAULT ISOLATION_READ_UNCOMMITED ISOLATION_COMMITED ISOLATION_REPEATABLE_READ ISOLATION_SERIALIZABLE ● 未授权读取(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个数据则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。 ● 授权读取(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。 ● 可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。 ● 序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。 ● 更新丢失(Lost update):两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。 ● 脏读取(Dirty Reads):一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。 ● 不可重复读取(Non-repeatable Reads):一个事务对同一行数据重复读取两次,但是却得到了不同的结果。例如,在两次读取的中途,有另外一个事务对该行数据进行了修改,并提交。 ● 两次更新问题(Second lost updates problem):无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。 ● 虚读(Phantom Reads):事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。 Dirty reads non-repeatable reads phantom reads SERIALIZABLE 不会 不会 不会 REPEATABLE READ 不会 不会 会 READ COMMITTED 不会 会 会 READ UNCOMMITTED 会 会 会 本文的讨论也很精彩,浏览讨论>> JavaEye推荐
xwork源代码--Configuration作者: 1998a 链接: http://1998a.javaeye.com/blog/228577 发表时间: 2008年08月16日 声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任! 1.com.opensymphony.xwork2.config.entities.PackageConfig 本文的讨论也很精彩,浏览讨论>> JavaEye推荐
struts2+spring+hibernate项目总结作者: coolworm 链接: http://coolworm.javaeye.com/blog/269196 发表时间: 2008年11月18日 声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任! 1、struts 2.0中的<s:textfield>标签 <s:textfield label="%{getText('label.login.userName')}"
name="userName"
tooltip="%{getText('label.login.userName.toolTip')}"
id="userName" />
label属性就指明了文本框前面的说明文本,没必要重新加入文字说明 2、在struts 2.0的标签中,国际化信息要用"%{getText('label.login.userName')}"这种形式 3、<s:head/>放置在<head></head>之间 将会引入struts tag用到的一些css和js文件 需要注意的是,如果任何ui tag或者ajax tag的theme属性值是ajax 那么<s:head>必须有theme属性 并且它的值是ajax 这将会额外地引入与ajax相关的js文件,比如dojo.js 如果没有引入,则会出现dojo不存在的错误 同时引入之后,可以在写javascript脚本时使用dojo框架,例如dojo,byId() 4、如果要自定义布局struts 2.0中的ui tag,则要设置ui tag必须加上theme="simple"才能进行自定义布局 5、在结合dwr的过程中,在页面要导入的javascript脚本是 <script type='text/javascript' src='/tmsot/dwr/interface/login.js'></script> <script type='text/javascript' src='/tmsot/dwr/engine.js'></script> <script type='text/javascript' src='/tmsot/dwr/util.js'></script> 但是engine.js、util.js文件没必要copy 6、当进行用户名是否存在验证的时候,如果多次输入错误,则会出现多条错误提示,同时,即使输入的是正确的也不能进入, <bean id="loginAction" class="com.lsxy.tmsoft.web.action.Login" abstract="false" lazy-init="default" autowire="default" dependency-check="default" scope="prototype"> <property name="userService"> <ref bean="userService" /> </property> </bean> 如图配置后就表明每次从spring容器中获取action.Login的实例的时候就会new一个新对象,即我们所说的原型,spring中scope默认的是单态(singleton),当然针对web应用程序,还可以配置为request、session等范围。至于什么时候使用什么权限范围就要看应用程序的使用了,比如在多线程程序中,单态是否会对程序有所影响就需要考虑了。 7、对struts.xml代码著一备注 <struts> <constant name="objectFactory" value="spring" /> <constant name="struts.custom.i18n.resources" value="globalMessages" /> <package name="default" extends="struts-default"> <action name="login" class="loginAction"> <result name="SUCCESS">/admin/index.jsp</result> <result name="input">/login.jsp</result> </action> </package> </struts> 要和spring结合请加<constant name="objectFactory" value="spring" /> 要国际化 <constant name="struts.custom.i18n.resources" value="globalMessages" /> 已有 0 人发表留言,猛击->> 这里<<-参与讨论 JavaEye推荐 |
互联网相关内容: |
| spring源代码学习(2.0.5)一(BeanFactory) (2008年07月06日) |
| 源代码解读Spring+Hibernate(JPA)的LazyLoadException异常 (2008年10月11日) |
| Spring配置总结 (2008年07月02日) |
| xwork源代码--Configuration (2008年08月16日) |
| struts2+spring+hibernate项目总结 (2008年11月18日) |
| mysql源代码安装 (2007年09月16日) |
| java 源代码地址 (2007年09月25日) |
| 开放源代码 - Wikipedia (2007年09月26日) |
| .NET FX库源代码 (2007年10月05日) |




