我有应用层 – >服务层 – > DAO层和所有的集合都是加载的.
所以,问题是在应用程序层(包含GUI / swing)的某个时刻,我使用服务层方法(包含@Transactional注释)加载一个实体,我想使用这个对象的一个惰性属性,但是可以直观地看到会话已经关闭
解决这个麻烦的最好办法是什么?
编辑
我尝试使用MethodInterceptor,我的想法是为所有实体编写一个AroundAdvice,并使用注释,例如:
// Custom annotation,say that session is required for this method @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Sessionrequired { // An AroundAdvice to intercept method calls public class SessionInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation mi) throws Throwable { bool sessionrequired=mi.getMethod().isAnnotationPresent(Sessionrequired.class); // Begin and commit session only if @Sessionrequired if(sessionrequired){ // begin transaction here } Object ret=mi.proceed(); if(sessionrequired){ // commit transaction here } return ret; } } // An example of entity @Entity public class Customer implements Serializable { @Id Long id; @OneToMany List<Order> orders; // this is a lazy collection @Sessionrequired public List<Order> getOrders(){ return orders; } } // And finally in application layer... public void foo(){ // Load customer by id,getCustomer is annotated with @Transactional // this is a lazy load Customer customer=customerService.getCustomer(1); // Get orders,my interceptor open and close the session for me... i hope... List<Order> orders=customer.getOrders(); // Finally use the orders }
解决方法
开始之前:检查抓取的个人资料实际上是否适合您.我没有自己使用它们,看到他们目前仅限于加入提取.在浪费时间实施和接线拦截器之前,请尝试手动设置抓取配置文件,看到它实际上可以解决您的问题.
有很多方法可以在Spring中设置拦截器(根据偏好),但最直接的方法是实现一个MethodInterceptor(见http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html#aop-api-advice-around).让它有一个设置器为您要获取的配置文件和设置为休眠会话工厂:
public class FetchProfileInterceptor implements MethodInterceptor { private SessionFactory sessionFactory; private String fetchProfile; ... setters ... public Object invoke(MethodInvocation invocation) throws Throwable { Session s = sessionFactory.openSession(); // The transaction interceptor has already opened the session,so this returns it. s.enableFetchProfile(fetchProfile); try { return invocation.proceed(); } finally { s.disableFetchProfile(fetchProfile); } } }
最后,在Spring配置中启用拦截器.这可以通过几种方式完成,您可能已经有一个可以将其添加到的AOP设置.见http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-schema.
如果您是AOP的新手,建议先尝试使用“旧”ProxyFactory方式(http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api .html#aop-api-proxying-intf),因为它更容易理解它是如何工作的.以下是一些示例XML,让您开始:
<bean id="fetchProfileInterceptor" class="x.y.zFetchProfileInterceptor"> <property name="sessionFactory" ref="sessionFactory"/> <property name="fetchProfile" ref="gui-profile"/> </bean> <bean id="businessService" class="x.y.x.BusinessServiceImpl"> <property name="dao" .../> ... </bean> <bean id="serviceForSwinGUI" class="org.springframework.aop.framework.Proxyfactorybean"> <property name="proxyInterfaces" value="x.y.z.BusinessServiceInterface/> <property name="target" ref="businessService"/> <property name="interceptorNames"> <list> <value>existingTransactionInterceptorBeanName</value> <value>fetchProfileInterceptor</value> </list> </property> </bean>