??xml version="1.0" encoding="utf-8" standalone="yes"?>
作? C
整理:robbin
原理Q利用Hibernate3提供的PostLoadEventListener在loadHibernate实体cȝ时候触发PostLoadEvent事gQ编写一个自定义的事件监听器Q注入依赖的Spring Bean对象
import org.hibernate.event.PostLoadEvent; import org.hibernate.event.PostLoadEventListener; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; public class SpringHibernateInjector implements PostLoadEventListener, BeanFactoryAware{ AutowireCapableBeanFactory beanFactory; public void onPostLoad(PostLoadEvent event) { Object hibernateObject = event.getEntity(); beanFactory.autowireBeanProperties(hibernateObject, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false); } public void setBeanFactory(BeanFactory factory) { beanFactory = (AutowireCapableBeanFactory) factory; } }
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="mappingResources"> <list> ...domains.hbm.xml here... </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.Oracle9Dialect </prop> <prop key="hibernate.query.substitutions"> true 1, false 0 </prop> <prop key="hibernate.show_sql">false</prop> </props> </property> <property name="eventListeners"> <map> <entry key="post-load"> <!-- This hibernate interceptor allows us to use Spring to inject services into Hibernate managed domain objects --> <bean class="yourpackage.SpringHibernateInjector"/> </entry> </map> </property> </bean>
注:此方法来自于ThoughtWorks?PerrynFowler
Q俺只是摘抄一?/P>
![]() |
![]() ![]() |
| |
我明白robbin你的意思,我说的情况就是网l传输导致的15U。本w页面执行的旉Q比如freemarker渲染一下模板,q个速度是非常快的,没问题,可是我的疑问在于如果网l传输狠慢,会不会媄响到数据库连接? 假设WebWork+Hibernate+FreeMarker架构模型是这L Request | |---other filters... | |---OpenSessionInView Filter | |-----WebWork Controller | |---Action | |---FreeMarker Result(对response.getWriter()做process()操作) | | |---OpenSessionInView Filter | |---other filters... | Request q里有两U情c? 一是页面缓冲区_大,_一ơ性容Ux有的面Q这h染页面就会一ơ性进入缓冲区Q然后返回到OpenSessionInView FilterQ关闭SessionQ数据库q接q回池中Q一切OK? W二U情冉|是重Ҏ讨论的,也是我的疑虑所在。那是假如q个面比较大,出叻页面缓冲区的大,那么渲染面Ӟ拿FreeMarker/Velocityq样的模板语a来说Q它执行process/mergeҎQ往servlet的response writer/outputStream里面写东西,写着写着Q发现写不动叻,是缓冲区满叻Q而这个writer/outputStreamQ正是服务器同用户之间徏立的sockethQ于是底层代码开始先向用户传输一部分面Q传好后Q又有叻新的~冲区,FreeMarker/Velocity的方法又能向~冲区里写东西叻。而传输页面这个过E,又耗费dU钟的时_导致叻数据库连接被占用ȝ长的旉? 可能我描q的是错误的Q希望robbin指正Q:Q?/SPAN> |
![]() |
![]() ![]() |
| |
我觉得这个问题归根结底就是AppServerI竟会如何实现页面输出。那么必然和具体的应用服务器实现有关pR那么至于每个AppServerI竟会怎样d玎ͼ我就不得而知了。v码大家可以研I一下Tomcat源代码看看tomcat是如何实现的? confluence采用的就是Hibernate/Spring/Webwork架构QOpenSessionInViewQ以confluenceq么q的使用Q好像也没有听过q方面的问题投诉?/SPAN> |
![]() |
![]() ![]() |
| |
我写了一个简单的webapp在Tomcat5.5.12上面做了一个小试。在JSP面里面循环1万次输出字符ԌE序在远E服务器上面q行Q网l是ADSL宽带Qfilter实被阻塞了20U左叟뀂然后我另外开了一个flashgetM载服务器上的大文Ӟ模拟|络速度比较慢的环境Qfilter被阻塞了50U左叟뀂分别做了三ơ测试。另外当面下蝲q程中直接点L览器stop按钮Q则JSP执行被打断,filter立刻解除dQ被执行完毕? l论证明Q用OpenSessionInView的时候,如果render的页面数据量非常大,q且客户端网l速度很慢的情况下Q由于页面的输出旉q程很长Q确实会造成filter被长旉d。对于OpenSessionInViewFilter来说Q就会造成数据库连接被保持很长的时_才能被关闭? 不过Q对于Spring的OpenSessionInViewFilter来说Q虽然数据库q接被保持了q长的时_但是q没有锁定数据库资源Q特别是事务资源。因为Spring的事务是通过TransactionInterceptor来实现的Q在MVCl构中,当最后一个业务bean被调用结束以后,Transaction已l被提交了。此后,虽然数据库连接还保持中,但是数据库资源没有锁定问题? 完整的调用示意图Q? request -> (OpenSessionInViewFilter打开Session) -> ServletDispatcher -> Action -> (打开ConnectionQ启动事? -> spring bean -> another spring bean -> (提交事务) -> bean执行完毕Q返回Action -> render view(JSP/Template) -> (OpenSessionInViewFilter关闭Session和Connection) |
![]() |
![]() ![]() | ||
| |||
robbin的分析很透彻Q对于最后一点,我稍有疑问?
其实我认为数据库q接被保持过长时间有时候会有很大的问题。尤其是对于采用数据q接池的情况Q如果你的数据库q接一直被保持Q那么这个资源就未被释放。假设说q个数据q接池的最大连接数?5Q我感觉很容易造成数据库的q接不够用? 不清楚底层的实现是如何做的,或许我的疑问有些多虑?/SPAN> |
![]() |
![]() ![]() | ||||
| |||||
按道理来_数据库连接应该尽早被释放Q以~解数据库资源的压力Qgq很久才释放Q确实会D需要更多的数据库连接。这个就只能扩大q接池数量,增加数据库最大允许连接数来解决了? 此外QSession被gq很久释放,那么Session占用的一U缓存也会占用比较长旉Q这意味着会无谓消耗更多的JVM内存? 因此QOpenSessionInView虽然实方便Q但是大家还是慎用吧。对于那些页面渲染速度很慢Q拨可接用h量过多的|站最好不要用?/SPAN> |
![]() |
![]() ![]() | ||
| |||
切的应该是大ƈ发用户量的情况吧。这个问题一直都存在Q在1q多前我和robbin争论中就提出来了q。hibernate2的代码可以看到session是和connection紧密耦合的(Hibernate3没看q)。但hibernate大部分被用于q发用户可预见的intranet应用Q所以问题也不是很大。如果ƈ发用户多Q对connection pool资源, opensession in view在hibernate中用会构成较大压力。如果jboss j2ee5 server采用hibernate作ؓejb3实现Q没有做修正的话Q同L问题也会存在于jboss j2ee5 server中?/SPAN> 上一ơ由Charlesxp?005-12-14 周三, 上午10:25修改Qd修改??/SPAN> |
![]() |
![]() ![]() | ||
| |||
在dao中对要render的集合强制初始化?/SPAN> |
![]() |
![]() ![]() | ||
| |||
Hibernate.initialize(foo.getBars); |
代码: |
package com.company.springaop.test; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class TestBeforeAdvice implements MethodBeforeAdvice { public void before(Method m, Object[] args, Object target) throws Throwable { System.out.println("Hello world! (by " + this.getClass().getName() + ")"); } } |
代码: |
package com.company.springaop.test; public class BeanImpl implements Bean { public void theMethod() { System.out.println(this.getClass().getName() + "." + new Exception().getStackTrace()[0].getMethodName() + "()" + " says HELLO!"); } } |
代码: |
package com.company.springaop.test; public interface Bean { public void theMethod(); } |
代码: |
package com.company.springaop.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Main { public static void main(String[] args) { //Read the configuration file ApplicationContext ctx = new FileSystemXmlApplicationContext("springconfig.xml"); //Instantiate an object Bean x = (Bean) ctx.getBean("bean"); //Execute the public method of the bean (the test) x.theMethod(); } } |
代码: |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!--CONFIG--> <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.company.springaop.test.Bean</value> </property> <property name="target"> <ref local="beanTarget"/> </property> <property name="interceptorNames"> <list> <value>theAdvisor</value> </list> </property> </bean> <!--CLASS--> <bean id="beanTarget" class="com.company.springaop.test.BeanImpl"/> <!--ADVISOR--> <!--Note: An advisor assembles pointcut and advice--> <bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="theBeforeAdvice"/> </property> <property name="pattern"> <value>com\.company\.springaop\.test\.Bean\.theMethod</value> </property> </bean> <!--ADVICE--> <bean id="theBeforeAdvice" class="com.company.springaop.test.TestBeforeAdvice"/> </beans> |