Nutz DAO懒加载实体关联对象

 

以前一直使用Hibernate,习惯了关联实体的懒加载。最近使用Nutz,里面没有提供懒加载的支持,于是乎自己扩展了一下Dao代码使其支持懒加载。这样用户在获取数据时就无需关心从dao抓取关联对象的问题了,调用POPO的getter方法时即可自动加载关联实体。下面就具体方案整理如下:
1. 定义一个名为LinkFieldGetterIntercepter的方法拦截器: 用于调用POJO的getter时自动加载关联对象。
2. 自定义一个EntityHolder: reloadEntity时创建实体代理类,添加第1条中定义的拦截器。并使用实体代理类在mappings中缓存实体。
3. 自定义一个org.nutz.dao.entity.Borning: 便于将ResultSet转换成POJO时,创建的是POJO的代理类实例,而不是POJO原始类实体。
4. 自定义一个EntityMaker: make方法中解析实体时setBorning(...)为第3条中定义的Borning对象。

下面是本人使用JPA作为POJO的annotation,扩展后的相关代码,如果直接使用Nutz annotation实现应该更简单。方法都是一样的。
1. LinkFieldGetterIntercepter:

public class LinkFieldGetterIntercepter extends AbstractMethodInterceptor {
	private static final Log log = Logs.getLog(LinkFieldGetterIntercepter.class);
	private Dao dao;
	private Link link;

	public LinkFieldGetterIntercepter(Dao dao, Link link) {
		this.dao = dao;
		this.link = link;
	}

	public Object afterInvoke(Object obj, Object returnObj, Method method, Object... args) {
		if (returnObj != null) {
			return returnObj;
		}
		String name = link.getOwnField().getName();
		dao.fetchLinks(obj, name);
		returnObj = Mirrors.getValue(obj, name);

		return returnObj;
	}
}

 

 

2. EntityHolder

public class DemsyEntityHolder {
	private Dao dao;// Dao 对象
	private EntityMaker maker;
	private Map<Class<?>, Entity<?>> mappings;// <AOP代理类,实体>
	private Map<Class, Class> agentClassMap;// <实体类,AOP代理类>

	public DemsyEntityHolder(DemsyNutDao dao) {
		this.dao = dao;
		this.maker = dao.getEntityMaker();
		mappings = new HashMap<Class<?>, Entity<?>>();
		agentClassMap = new HashMap<Class, Class>();
	}

	public <T> Entity<T> getEntity(Class<T> classOfT) {
		// 转换成AOP代理类
		if (!Mirrors.isAgent(classOfT)) {
			classOfT = agentClassMap.get(classOfT);
		}
		if (classOfT == null) {
			return null;
		}

		return (Entity<T>) mappings.get(classOfT);
	}

	@SuppressWarnings("unchecked")
	public <T> Entity<T> reloadEntity(Class<T> classOfT, boolean autoCreateTable) {
		JPAEntity<?> entity = (JPAEntity<?>) maker.make(null, null, classOfT);

		// 缓存实体
		mappings.put(agentClass(entity), entity);

		return (Entity<T>) entity;
	}

	// 创建代理类
	private Class agentClass(JPAEntity entity) {
		Class cls = entity.getType();
		if (Mirrors.isAgent(cls)) {
			return cls;
		}

		ClassAgent classAgent = new AsmClassAgent();
		List<Link> links = entity.getLinks(null);
		if (links != null) {
			for (Link link : links) {
				String fieldName = link.getOwnField().getName();
				fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
				classAgent.addInterceptor(MethodMatcherFactory.matcher("get" + fieldName),
						new LinkFieldGetterIntercepter(dao, link));
			}
		}
		Class agentClass = classAgent.define(new DefaultClassDefiner(), cls);

		entity.setAgentMirror(Mirror.me(agentClass));

		this.agentClassMap.put(cls, agentClass);

		return agentClass;
	}

	public int count() {
		return mappings.size();
	}
}

 

3 Borning:

class DemsyBorning implements Borning {
	JPAEntity entity;

	DemsyBorning(JPAEntity entity) {
		this.entity = entity;
	}

	/**
	 * 创建实体代理实例
	 * 
	 * @return
	 * @throws Exception
	 */
	public Object create() throws Exception {
		//创建代理类的实例,而不是原始类的实例
		return entity.getAgentMirror().born();
	}

	public Object born(ResultSet rs, FieldMatcher fm) throws Exception {
		Object obj = create();
		Iterator<EntityField> it = entity.fields().iterator();
		while (it.hasNext()) {
			EntityField ef = it.next();
			if (null == fm || fm.match(ef.getField().getName()))
				ef.fillValue(obj, rs);
		}
		return obj;
	}
}

 

 

4 EntityMaker:

 

......
public Entity<?> make(DatabaseMeta db, Connection conn, Class<?> type) {
......
		// Borning
		entity.setBorning(new DemsyBorning(entity));
......











你可能感兴趣的:(DAO,AOP,Hibernate,jpa,IOC)