`
yongshan.ji
  • 浏览: 3346 次
  • 性别: Icon_minigender_1
  • 来自: 自己输入城市...昆明
文章分类
社区版块
存档分类
最新评论

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));
......











分享到:
评论
2 楼 wendal 2010-04-26  
   挺不错的.
1 楼 zozoh 2010-04-23  
Wendal~兽<t23@tom.com>  12:03:37
很好很强大
Wendal~兽<t23@tom.com>  12:09:07
但是, LinkFieldGetterIntercepter  好像有点问题
Wendal~兽<t23@tom.com>  12:09:23
#         if (link.isOne()) { 
#  
#         } else if (link.isMany()) { 
#  
#         } else if (link.isManyMany()) { 
#  
#         }
Wendal~兽<t23@tom.com>  12:09:34
结果还是什么都没执行...
灰太狼(108594100)  12:09:42
public LinkFieldGetterIntercepter(Dao dao, Link link)
灰太狼(108594100)  12:09:54
好像没法构造吧
Wendal~兽<t23@tom.com>  12:10:37
why?
灰太狼(108594100)  12:11:03
Link 怎么传?
灰太狼(108594100)  12:11:18
拦截器通过 @Aop 声明
灰太狼(108594100)  12:11:32
Ioc 容器怎么能传 Link 进去?
Wendal~兽<t23@tom.com>  12:11:41
他这是实现,不是通过@Aop的
Wendal~兽<t23@tom.com>  12:12:12
他直接调用ClassAgent来构建Aop类
灰太狼(108594100)  12:18:01
一直以为他要用 IOC
灰太狼(108594100)  12:18:09

Wendal~兽<t23@tom.com>  12:18:10

灰太狼(108594100)  12:19:11
DemsyEntityHolder  好像就是一个独立的类
灰太狼(108594100)  12:21:04
哦,我说呢
灰太狼(108594100)  12:21:12
他没给出 DemsyNutDao 的代码
Wendal~兽<t23@tom.com>  12:21:13

灰太狼(108594100)  12:21:23
那里面应该用了 DemsyEntityHolder
Wendal~兽<t23@tom.com>  12:21:36
好像没有需要特定的类吧
Wendal~兽<t23@tom.com>  12:22:11
哦,好像是
灰太狼(108594100)  12:24:13
他的需求是

Pet pet = dao.fetch(Pet.class, "XiaoBai"); 
// => SELECT * FROM t_pet WHERE name='XiaoBai';
Master m = pet.getMaster();
// => SELECT * FROM t_master WHERE id=34;
灰太狼(108594100)  12:24:45
所以需要 Dao 对象在 fetch 的时候对 Pet 做 Aop
Wendal~兽<t23@tom.com>  12:24:59

灰太狼(108594100)  12:25:06
所以这个 Dao 必须是自己扩展的 Dao
Wendal~兽<t23@tom.com>  12:25:32

灰太狼(108594100)  12:25:45
它需要覆盖 getEntity 和 getEntityMaker
灰太狼(108594100)  12:25:54
基本就可以搞定了
Wendal~兽<t23@tom.com>  12:26:03
除非你添加一个@Lazy标签
Wendal~兽<t23@tom.com>  12:26:13
@Lazy 注解
灰太狼(108594100)  12:26:22
他统统 Lazy 啊
Wendal~兽<t23@tom.com>  12:26:40

Wendal~兽<t23@tom.com>  12:26:46
应该不是吧
灰太狼(108594100)  12:27:28
是啊, Fetch 的时候,做个 Aop, 监视所有 @Many, @One 和 @ManyMany
灰太狼(108594100)  12:27:41
效率没有损失吧
Wendal~兽<t23@tom.com>  12:27:49
但是,有必要不?
灰太狼(108594100)  12:28:41
如果觉得没有必要, 你为啥用 DemsyNutDao  呢?
Wendal~兽<t23@tom.com>  12:28:52

灰太狼(108594100)  12:28:58
直接用 NutDao 就好了,那个是完全没有 Lazy 的
天行健(119588911)  12:29:46

这些是代码模板,因为我的是基于JPA的所以只提供了一个模板
Wendal~兽<t23@tom.com>  12:30:26
哦....
灰太狼(108594100)  12:30:29
我觉得应该提供三种 GetterIntercepter
灰太狼(108594100)  12:31:07
在 EntityHolder 里判断 Link 的类型而决定用哪种 GetterIntercepter
天行健(119588911)  12:31:12

我的dao是有其他用途,代码部分只是当做模板参考。
灰太狼(108594100)  12:31:17
这样在运行时就不用这么判断了
天行健(119588911)  12:32:05
是可以这样

相关推荐

    Nutz框架文档

    活 -- 各个部分可以独立使用,比如在 Spring 里采用 Nutz.Dao ,又比如在 Nutz.Ioc 里使用 Hibernate 等 整 -- 它所有功能均不依赖第三方 jar 文件。 这就意味着:如果一个 Web 应用,你在 WEB-INF/lib 下只 需要...

    高效,小巧的开源JAVA WEB 开发框架-Nutz (源码,开发文档)

    数据库访问层 -- Nutz.Dao 反转注入支持 -- Nutz.Ioc Mvc 框架 -- Nutz.Mvc Json 解析器 -- Nutz.Json 更多的简化Java语法的函数和类 -- Nutz.Lang 以及 Nutz.Castors 不依赖任何第三方 Jar 包,从而便于程序员建立...

    nutz-1.b.52.zip

    如果你觉得 Hibernate 控制比较繁琐,iBatis 编写SQL又比较麻烦,Nutz.Dao 专为你设计。 如果你觉得在多个服务器部署或者修改 Spring 配置文件很麻烦,Nutz.Ioc 专为你设计 如果你觉得直接写 XML 配置文件很麻烦,...

    Nutz-1.b.38

    Spring 里采用 Nutz.Dao ,又比如在 Nutz.Ioc 里使用 Hibernate 等整 -- 它所有功能均不依赖第三方 jar 文件。这就意味着:如果一个 Web 应用,你在 WEB-INF/lib 下只 需要放置一个 nutz.jar 就够了当然你要使用其它...

    nutz 使用手册 nutz-1.a.33-manual.pdf

    nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册 nutz 使用手册

    nutz pdf学习文档

    活 -- 各个部分可以独立使用,比如在 Spring 里采用 Nutz.Dao ,又比如在 Nutz.Ioc 里使用 Hibernate 等 整 -- 它所有功能均不依赖第三方 jar 文件。这就意味着:如果一个 Web 应用,你在 WEB-INF/lib 下只 需要放置...

    在Nutz[1.b.38]中使用视图对关联数据表的操作

    NULL 博文链接:https://gevin.iteye.com/blog/1147922

    nutzDao增删改查Demo

    nutzDao增删改查Demo

    nutz邮箱验证jar包

    用于nutz邮箱验证jar包

    nutz生成javabean工具.zip

    nutz生成javabean工具.zip

    nutz代码生成器

    nutz框架代码生成器,配置数据源后点击生成类,勾选数据表自动生成Action及实体类

    nutz框架使用手册.zip

    nutz框架使用手册,从零到有深入学习nutz平台开发

    nutz插件 定位页面路径

    可以快速定位路径 页面 本jar包是nutz实用插件 希望大家多多下载

    nutz-1.r.58

    nutz框架jar包

    nutz框架开发手册

    nutz框架开发手册,框架很方便使用的,和大家分享

    nutz_redis集成依赖包

    在做nutz redis集成的实时,由于依赖包的问题被坑了一把,为了后人不要走同样的路,把所有依赖包放在上面了。

    springboot+nutz+beetl整合工程

    dao层使用nutz,view层使用beetl,数据源使用阿里的druid

    nutz的freemarker视图插件

    让nutz支持freemarker。 具体使用和在struts2中使用是一样的

    nutz搭建的MVC框架

    用开源框架nutz搭建的MVC框架,适合小型系统的开发,快捷方便!

Global site tag (gtag.js) - Google Analytics