`
yiyanwan77
  • 浏览: 187745 次
  • 性别: Icon_minigender_1
  • 来自: 威海
社区版块
存档分类
最新评论

aop解决flex blazeds+jpa(hibernate)延迟加载抛出session关闭异常的问题

阅读更多
  • 问题简单描述

项目中后台使用hibernate实现的jpa作为持久层,当blazeds解析返回数据包含未加载项时,触发了延迟加载动作,而此时事物已经结束,于是抛出session关闭异常。

  • 解决思路

后台通过jpa返回的数据结果其实为动态代理创建的该类型的子类,调用这些对象的get方法时,动态代理子类的包装壳判断是否加载了数据(通过查看hibernate源码,可以得知有个initialized属性标记),如果没有,则查询该项。因此,只要避免转换时触发加载动作就可以解决该问题,简单想来有以下几种方案:

  1. aop切到最外的service层,得到返回结果,递归遍历属性,判断是否加载了属性(基本属性不存在这个问题)-注意,即使属性未加载,该属性值并不为空,而是一个代理对象),如果没有加载则想办法使其返回空(考虑过使用动态代理的方式,未能解决)
  2. 还是用aop,得到返回结果后,创建新的实例返回,依然要判断是否加载,如果已加载则返回真实值 (因为得到的对象为动态代理类,在对象为集合的时候获取实际类有点困难,我暂未能获知该途径,若有知情人,还望不吝赐教)
  3. 上面两种方案都需要增加递归遍历过程,对性能时有影响的,特别时第二种,所有属性都要重新创建,开销比较大。因此最佳方案应该时直接修改blazeds的源码,返回结果处理时,再用上述第一种方案的思路。
  • 实现

因为项目时间上的压力,考虑从第一种方案入手,在实际解决的过程中仍然遇到了重重困难,无数次断点调试后发现了了如下规律:如果返回值为集合,则获取到的类名为PersistenceSet(实际上并非所有集合都是用Set代理 ),而如果为单个对象则类名中含有_$$_javasis..等内容(该规则与动态代理的实现有关),后来查看hibernate源码,发现代理其实为PersistentCollection或HibernateProxy接口的实现类,大部分问题都解决了,但是最后遇到子项加载父项时,如果直接置空属性,则将更新(此时session已经关闭,但实际上更新确成功了,这个现象一直没弄明白 ),尝试用动态代理解决,没有成功。最后,迫于项目时间压力,暂时再该期使用了第二种实现方式:

 

org.hibernate.collection.*

PersistentSet extends AbstractPersistentCollection implements java.util.Set

AbstractPersistentCollection implements Serializable, PersistentCollection

PersistentArrayHolder extends AbstractPersistentCollection

PersistentBag extends AbstractPersistentCollection implements List

PersistentElementHolder extends AbstractPersistentCollection

PersistentIdentifierBag extends AbstractPersistentCollection implements List

PersistentIndexedElementHolder extends AbstractPersistentCollection

PersistentList extends AbstractPersistentCollection implements List

PersistentListElementHolder extends PersistentIndexedElementHolder

PersistentMap extends AbstractPersistentCollection implements Map

PersistentMapElementHolder extends PersistentIndexedElementHolder

PersistentSet extends AbstractPersistentCollection implements java.util.Set

PersistentSortedMap extends PersistentMap implements SortedMap

PersistentSortedSet extends PersistentSet implements SortedSet

 

 

LazyAspect.java

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.proxy.HibernateProxy;


/**
 * 解决使用延迟加载配置,且service层返回时该项未加载时,blazeds抛出session关闭的问题
 * 
 * @author 王逸群
 * @date 2011-10-8
 */
public class LazyAspect {

	private static Logger log = Logger.getLogger(LazyAspect.class);

	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		try {
			Object retVal = pjp.proceed();
			Object safeObject = safeCopy(retVal);
			return safeObject;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}

	}

	/**
	 * 不触发延迟加载的深度拷贝
	 * 
	 * @param obj
	 *            拷贝对象
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws InstantiationException
	 */
	public Object safeCopy(Object obj) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			InstantiationException {
		return _safeCopy(obj, new HashMap<Object, Object>());
	}

	/**
	 * 不触发延迟加载的深度拷贝
	 * 
	 * @param obj
	 *            拷贝对象
	 * @param copiedMap
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws InstantiationException
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private Object _safeCopy(Object obj, Map<Object, Object> copiedMap)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, InstantiationException {

		// 基本类型不可能为代理,直接返回
		if (isPrimitive(obj)) {
			return obj;
		}

		// 如果已经解析,直接从map中获取
		if (copiedMap.containsKey(obj)) {
			return copiedMap.get(obj);
		}

		Class clazz = obj.getClass();
		

		// Collection对象
		if (obj instanceof Collection) {
			Collection $collection = null;

			// PersistentCollection 代理
			if (obj instanceof PersistentCollection) {
				PersistentCollection $persistentCollection = (PersistentCollection) obj;

				// 已经加载字段
				if ($persistentCollection.wasInitialized()) {
					if ($persistentCollection instanceof Set) {
						//暂无法获取集合实际类
						$collection = new HashSet();
					} else if ($persistentCollection instanceof List) {
						//暂无法获取集合实际类
						$collection = new ArrayList();
					}
				}

				// 未加载
				else {
					copiedMap.put(obj, null);
					return null;
				}
			}

			// 非PersistentCollection代理集合
			else {
				$collection = (Collection) obj.getClass().newInstance();
			}
			Iterator itr = ((Collection) obj).iterator();
			if (itr != null)
				while (itr.hasNext()) {
					$collection.add(_safeCopy(itr.next(), copiedMap));
				}
			copiedMap.put(obj, $collection);
			return $collection;
		}

		// Map
		else if (obj instanceof Map) {
			Map $map = null;
			Map map = (Map) obj;

			// 代理
			if (obj instanceof PersistentCollection) {
				PersistentCollection $persistentCollection = (PersistentCollection) obj;
				// 已加载
				if ($persistentCollection.wasInitialized()) {
					//暂无法获取集合实际类
					$map = new HashMap();
				}
				// 未加载
				else {
					copiedMap.put(obj, null);
					return null;
				}
			}
			// 非代理对象
			else {
				$map = (Map) obj.getClass().newInstance();
			}

			for (Object ele : map.keySet()) {
				$map.put(ele, _safeCopy(map.get(ele), copiedMap));
			}
			copiedMap.put(obj, $map);
			return $map;
		}

		// 数组
		else if (clazz.isArray()) {
			int len = Array.getLength(obj);

			if (len > 0) {

				String arrClassName=clazz.getName();
				String className=arrClassName.substring(arrClassName.indexOf("L")+1,arrClassName.length()-1);
				
				// 注意,这里创建的实例非Array
				Object $arr = Array.newInstance(Class.forName(className), len);
				 
				for (int i = 0; i < len; i++) {
					Array.set($arr, i, _safeCopy(Array.get(obj, i), copiedMap));
				}
				copiedMap.put(obj, $arr);
				return $arr;
			} else {
				copiedMap.put(obj, null);
				return null;
			}

		}
		// 代理
		if (obj instanceof HibernateProxy) {
			HibernateProxy proxy = (HibernateProxy) obj;
			// 已加载
			if (!proxy.getHibernateLazyInitializer().isUninitialized()) {
				Object $obj = _safeCopy(proxy.getHibernateLazyInitializer()
						.getImplementation(), copiedMap);
				copiedMap.put(obj, $obj);
				return $obj;
			}
			// 未加载
			else {
				copiedMap.put(obj, null);
				return null;
			}
		}

		// 普通类
		else {

			Object $obj = obj.getClass().newInstance();
			copiedMap.put(obj, $obj);

			// 解析属性
			Field[] fields = obj.getClass().getDeclaredFields();
			for (Field field : fields) {
				String subFieldName = field.getName();
				Object fieldValue = null;
				
				// 类中可能有不可读属性(指非标准setter,getter访问方式),比如public static
				if(PropertyUtils.isReadable(obj, subFieldName)){
					fieldValue = PropertyUtils.getProperty(obj, subFieldName);
				}
				// 属性值为空或者无法读取的不处理
				if (fieldValue != null) {
					PropertyUtils.setProperty($obj, subFieldName,
							_safeCopy(fieldValue, copiedMap));
				}
			}

			return $obj;
		}
	}

	/**
	 * 是否为基本类型,注意,与jdk api中的isPrimitive规则不同
	 * 
	 * @param obj
	 * @return
	 */
	public boolean isPrimitive(Object obj) {
		if (obj == null) {
			return true;
		}
		Class clazz = obj.getClass();
		if (clazz.isPrimitive()) {
			return true;
		}
		String className = clazz.getName();
		return className.indexOf("java") == 0 && (!(obj instanceof Collection))
				&& (!(obj instanceof Map)) && (!clazz.isArray());
	}
}
分享到:
评论

相关推荐

    PureMVC+Flex+BlazeDS+Spring+Hibernate.doc

    标题中的“PureMVC+Flex+BlazeDS+Spring+Hibernate.doc”指的是一项整合了多种技术的Web应用开发方案,这些技术包括PureMVC、Flex、BlazeDS、Spring和Hibernate。这篇文档可能是指导读者如何将这些技术结合在一起...

    Flex4.X+BlazeDS+Spring3L实战开发在线书店二

    综上所述,这个在线书店的开发实例结合了Flex 4.6的富用户体验、BlazeDS的数据通信能力、Spring 3的依赖注入和业务管理、JPA的持久化机制以及Hibernate和MySQL的数据库支持。通过学习和实践这个项目,你将能够掌握...

    Flex4.X+BlazeDS+Spring3L实战开发在线书店四

    【标题】"Flex4.X+BlazeDS+Spring3实战开发在线书店四"涉及的核心技术栈是Adobe Flex 4.6、BlazeDS、Spring 3框架以及Java相关的JPA和Hibernate,配合MySQL数据库实现一个在线书店的完整系统。下面将详细阐述这些...

    Flex4+BlazeDS+Spring+Hibernate 整合源码

    在“Flex4+BlazeDS+Spring+Hibernate 整合源码”中,开发者可能实现了以下功能: 1. 使用Flex4创建前端用户界面,包括自定义组件和动画效果。 2. 通过BlazeDS配置,实现在Flex客户端与Spring服务层之间的数据双向...

    Flex4.X+BlazeDS+Spring3L实战开发在线书店三

    《Flex4.X+BlazeDS+Spring3 实战开发在线书店》是一门深入探讨使用Adobe Flex 4.6、BlazeDS、Spring 3框架以及Java相关技术进行Web应用程序开发的课程。这门课程旨在帮助开发者掌握如何构建功能丰富的、交互性强的...

    PureMVC+Flex+BlazeDS+Spring+Hibernate

    标题中的“PureMVC+Flex+BlazeDS+Spring+Hibernate”是一个常见的技术栈组合,用于构建企业级的 Rich Internet Applications (RIA)。这个技术栈包括前端开发框架、后端服务通讯、应用服务器、服务端架构和数据持久化...

    flex4+blazeds+spring+hibernate集成

    集成Flex4、BlazeDS、Spring和Hibernate可以构建出高度互动的前端和强大后端相结合的Web应用。这种架构使得开发人员可以充分利用Flex的富客户端能力,同时利用Spring和Hibernate的强大功能处理业务逻辑和数据库操作...

    Myeclipse6.5+flex3+Blazeds+spring+hibernate完美整合源代码

    总结一下,"Myeclipse6.5+flex3+Blazeds+spring+hibernate完美整合源代码"代表了一个完整的、成熟的开发解决方案,它结合了现代Web开发的多个关键组件,提供了从前端用户界面到后端数据存储的全面支持。配合相应的...

    spring+springMVC+jpa+hibernate框架整合

    在IT领域,构建高效、可扩展的Web应用是至关重要的,而"spring+springMVC+jpa+hibernate框架整合"就是一个常见的解决方案。这个整合涉及到四个关键的技术栈:Spring框架、SpringMVC、JPA(Java Persistence API)...

    Flex+spring+hibernate示例

    Flex+Spring+Hibernate示例是一种常见的企业级应用架构,它结合了Adobe Flex前端技术、Spring后端框架和Hibernate持久层框架,以构建高效、灵活且易于维护的Web应用程序。在这个示例中,开发者可能已经展示了如何...

    Springmvc+JPA(Hibernate4)+redis+activemq

    **Spring MVC + JPA(Hibernate4) + Redis + ActiveMQ:构建高效、全面的Web应用** Spring MVC 是Spring框架的一部分,专门用于构建Web应用程序的模型-视图-控制器(MVC)架构。它提供了一个灵活的请求处理机制,...

    spring3+springmvc+jpa+hibernate多数据源

    "spring3+springmvc+jpa+hibernate多数据源"是一个示例项目,它演示了如何在一个应用中集成Spring 3、Spring MVC、JPA 2.0以及Hibernate,以实现对多个数据源的支持。下面将详细介绍这些技术及其集成的关键点。 **...

    Spring+Jersey+JPA+Hibernate+MySQL整合

    在本项目中,Spring被用来整合其他技术,如Jersey、JPA和Hibernate,以实现一个完整的Web服务解决方案。 Jersey是Java RESTful Web Services(RESTful API)的实现,它基于JSR 311和JSR 339标准。通过使用Jersey,...

    spring+springmvc+hibernate+jpa搭建

    在IT行业中,构建一个基于Spring、SpringMVC、Hibernate和JPA的开发环境是常见的任务,这四个组件都是Java企业级应用开发中的重要工具。让我们深入探讨这些技术以及如何将它们整合在一起搭建一个完整的开发环境。 *...

    Spring + JPA + Hibernate配置

    标题“Spring + JPA + Hibernate配置”涉及到的是Java开发中常用的三个框架——Spring、Java Persistence API (JPA) 和Hibernate的集成与配置。这是一份关于如何将这些框架结合使用的教程或参考资料,可能包含了实现...

    Flash Builder 4 + BlazeDs + Spring + Hibernate + Cairngorm开发框架

    通过使用AMF(Action Message Format)协议,BlazeDs能够实现低延迟、高效率的数据传输,使得Flex应用能够与Java服务进行实时通信。 Spring框架是Java领域中广泛使用的轻量级应用框架,它简化了Java企业级应用的...

    flex+java+spring+hibernate+blazeds整合

    《Flex+Java+Spring+Hibernate+BlazeDS整合详解》 在现代的Web开发中,Flex作为客户端的富互联网应用程序(RIA)框架,与Java、Spring、Hibernate等后端技术结合,可以构建出高效、交互性强的Web应用。本文将详细...

    Flex+Blazeds+Spring+Hibernet+Mysql整合工程,导入eclipse即可

    Flex+Blazeds+Spring+Hibernate+MySQL是一个经典的Java企业级开发组合,它结合了前端的富互联网应用程序(RIA)开发框架Flex与后端的强大数据处理能力,通过Blazeds作为中间层通信桥梁,利用Spring进行服务管理和...

    Flex4.X+BlazeDS+Spring3L实战开发在线书店一

    在"基于Flex4.X+BlazeDS+Spring3+JPA+Hibernate+MySQL实战开发在线二.exe"这个文件中,很可能是项目的源代码或者是一个可执行程序,它展示了如何整合所有这些技术。MySQL是常用的开源关系型数据库,用于存储和管理...

Global site tag (gtag.js) - Google Analytics