diff --git a/src/org/nutz/dao/impl/EntityHolder.java b/src/org/nutz/dao/impl/EntityHolder.java index d8e315a11..ae0898362 100644 --- a/src/org/nutz/dao/impl/EntityHolder.java +++ b/src/org/nutz/dao/impl/EntityHolder.java @@ -26,7 +26,7 @@ public class EntityHolder { // DaoSupport 会设置这个值 - EntityMaker maker; + public EntityMaker maker; private DaoSupport support; diff --git a/src/org/nutz/dao/impl/SimpleDataSource.java b/src/org/nutz/dao/impl/SimpleDataSource.java index 303b3ebd4..13b19e4eb 100644 --- a/src/org/nutz/dao/impl/SimpleDataSource.java +++ b/src/org/nutz/dao/impl/SimpleDataSource.java @@ -23,9 +23,12 @@ public class SimpleDataSource implements DataSource { private String jdbcUrl; public Connection getConnection() throws SQLException { + Connection conn; if (username != null) - return DriverManager.getConnection(jdbcUrl, username, password); - return DriverManager.getConnection(jdbcUrl); + conn = DriverManager.getConnection(jdbcUrl, username, password); + else + conn = DriverManager.getConnection(jdbcUrl); + return conn; } public void close() {} diff --git a/src/org/nutz/dao/impl/entity/AnnotationEntityMaker.java b/src/org/nutz/dao/impl/entity/AnnotationEntityMaker.java index 825e110bb..5216dc5fe 100644 --- a/src/org/nutz/dao/impl/entity/AnnotationEntityMaker.java +++ b/src/org/nutz/dao/impl/entity/AnnotationEntityMaker.java @@ -75,7 +75,7 @@ public AnnotationEntityMaker(DataSource datasource, JdbcExpert expert, EntityHol } public Entity make(Class type) { - NutEntity en = new NutEntity(type); + NutEntity en = _createNutEntity(type); TableInfo ti = _createTableInfo(type); @@ -496,4 +496,7 @@ private void _checkupEntityFieldsWithDatabase(NutEntity en) { } } + protected NutEntity _createNutEntity(Class type) { + return new NutEntity(type); + } } diff --git a/src/org/nutz/dao/impl/entity/LinkFieldSet.java b/src/org/nutz/dao/impl/entity/LinkFieldSet.java index 4d21c941e..ee784965d 100644 --- a/src/org/nutz/dao/impl/entity/LinkFieldSet.java +++ b/src/org/nutz/dao/impl/entity/LinkFieldSet.java @@ -15,7 +15,7 @@ * * @author zozoh(zozohtnt@gmail.com) */ -class LinkFieldSet { +public class LinkFieldSet { private ArrayList lnks; @@ -30,7 +30,7 @@ void add(LinkField lnk) { lnks.add(lnk); } - List getAll() { + public List getAll() { return lnks; } diff --git a/src/org/nutz/dao/impl/entity/NutEntity.java b/src/org/nutz/dao/impl/entity/NutEntity.java index 5f34be334..4ae8db4a0 100644 --- a/src/org/nutz/dao/impl/entity/NutEntity.java +++ b/src/org/nutz/dao/impl/entity/NutEntity.java @@ -71,17 +71,17 @@ public class NutEntity implements Entity { /** * 所有一对一映射字段 */ - private LinkFieldSet ones; + protected LinkFieldSet ones; /** * 所有一对多映射字段 */ - private LinkFieldSet manys; + protected LinkFieldSet manys; /** * 所有多对多映射字段 */ - private LinkFieldSet manymanys; + protected LinkFieldSet manymanys; /** * 数字型主键 @@ -96,7 +96,7 @@ public class NutEntity implements Entity { /** * 实体 Java 类型 */ - private Class type; + protected Class type; /** * 实体 Java 类型:通过 Mirror 增强 @@ -111,7 +111,7 @@ public class NutEntity implements Entity { /** * 根据默认构造函数或者工厂方法创建实体的方法 */ - private Borning bornByDefault; + protected Borning bornByDefault; /** * 实体表名 diff --git a/src/org/nutz/dao/impl/ext/LazyAnnotationEntityMaker.java b/src/org/nutz/dao/impl/ext/LazyAnnotationEntityMaker.java new file mode 100644 index 000000000..9460c18b4 --- /dev/null +++ b/src/org/nutz/dao/impl/ext/LazyAnnotationEntityMaker.java @@ -0,0 +1,142 @@ +package org.nutz.dao.impl.ext; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; + +import org.nutz.aop.ClassAgent; +import org.nutz.aop.ClassDefiner; +import org.nutz.aop.DefaultClassDefiner; +import org.nutz.aop.InterceptorChain; +import org.nutz.aop.MethodInterceptor; +import org.nutz.aop.asm.AsmClassAgent; +import org.nutz.aop.matcher.MethodMatcherFactory; +import org.nutz.dao.Dao; +import org.nutz.dao.entity.Entity; +import org.nutz.dao.entity.LinkField; +import org.nutz.dao.impl.EntityHolder; +import org.nutz.dao.impl.entity.AnnotationEntityMaker; +import org.nutz.dao.impl.entity.NutEntity; +import org.nutz.dao.jdbc.JdbcExpert; +import org.nutz.ioc.aop.config.InterceptorPair; +import org.nutz.lang.Mirror; +import org.nutz.lang.Strings; +import org.nutz.log.Log; +import org.nutz.log.Logs; + +/** + * 支持简单的懒加载机制的AnnotationEntityMaker + * @author wendal(wendal1985@gmail.com) + * + */ +public class LazyAnnotationEntityMaker extends AnnotationEntityMaker { + + private static final Log log = Logs.get(); + + private Dao dao; + + private ClassDefiner cd; + + public LazyAnnotationEntityMaker(DataSource datasource, JdbcExpert expert, + EntityHolder holder, Dao dao) { + super(datasource, expert, holder); + this.dao = dao; + cd = new DefaultClassDefiner(getClass().getClassLoader()); + } + + protected NutEntity _createNutEntity(Class type) { + return new LazyNutEntity(type); + } + + @Override + public Entity make(Class type) { + LazyNutEntity en = (LazyNutEntity) super.make(type); + en.init(); + return en; + } + + class LazyNutEntity extends NutEntity{ + + public LazyNutEntity(Class type) { + super(type); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void init() { + //仅支持通过默认构造进行构建的类, TODO 支持Result方式生成对象的构造方法 + if (this.bornByDefault != null) { + //检查是否需要进行Lazy处理 + if (!ones.getAll().isEmpty() || !manys.getAll().isEmpty() || !manymanys.getAll().isEmpty()) { + if (log.isDebugEnabled()) + log.debug("Found links , enable lazy!! -->" + type); + try { + Class klass = cd.load(type.getName() + ClassAgent.CLASSNAME_SUFFIX); + this.bornByDefault = Mirror.me(klass).getBorning(); + return; + } + catch (ClassNotFoundException e) {}//事实上,这里肯定是ClassNotFound的 + + Mirror mirror = Mirror.me(type); + List interceptorPairs = new ArrayList(); + List lfs = new ArrayList(); + lfs.addAll(ones.getAll()); + lfs.addAll(manys.getAll()); + lfs.addAll(manymanys.getAll()); + //准备拦截器 + for (LinkField lf : lfs) { + String fieldName = lf.getName(); + try { + Method setter = mirror.getSetter(mirror.getField(fieldName)); + LazyMethodInterceptor lmi = new LazyMethodInterceptor(setter, fieldName); + interceptorPairs.add(new InterceptorPair(lmi, MethodMatcherFactory.matcher("^(get|set)"+Strings.capitalize(fieldName)+"$"))); + } catch (Throwable e) { + if (log.isWarnEnabled()) + log.warn("Not setter found for LazyLoading ?!", e); + } + } + //生成Aop化的类 + ClassAgent agent = new AsmClassAgent(); + for (InterceptorPair interceptorPair : interceptorPairs) + agent.addInterceptor( interceptorPair.getMethodMatcher(), + interceptorPair.getMethodInterceptor()); + Class lazyClass = agent.define(cd, type); + this.bornByDefault = Mirror.me(lazyClass).getBorning(); + } + } + } + } + + class LazyMethodInterceptor implements MethodInterceptor { + + private LazyStatus status = LazyStatus.CAN_FETCH; + + private Method setter; + private String fieldName; + + public LazyMethodInterceptor(Method setter, String fieldName) { + this.setter = setter; + this.fieldName = fieldName; + } + + + public void filter(InterceptorChain chain) throws Throwable { + if (status == LazyStatus.CAN_FETCH) { + if (chain.getCallingMethod() != setter) { + dao.fetchLinks(chain.getCallingObj(), fieldName);//这里会触发setter被调用 + status = LazyStatus.FETCHED; + } else + status = LazyStatus.NO_NEED; //如果setter被调用,那么也就不再需要懒加载了 + } + chain.doChain(); + } + + } + + enum LazyStatus { + CAN_FETCH, + FETCHED, + NO_NEED + } +} diff --git a/src/org/nutz/dao/impl/ext/LazyNutDao.java b/src/org/nutz/dao/impl/ext/LazyNutDao.java new file mode 100644 index 000000000..70136f5bb --- /dev/null +++ b/src/org/nutz/dao/impl/ext/LazyNutDao.java @@ -0,0 +1,47 @@ +package org.nutz.dao.impl.ext; + +import javax.sql.DataSource; + +import org.nutz.aop.AopCallback; +import org.nutz.dao.SqlManager; +import org.nutz.dao.entity.Entity; +import org.nutz.dao.entity.EntityMaker; +import org.nutz.dao.impl.EntityHolder; +import org.nutz.dao.impl.NutDao; + +/** + * 支持简单的懒加载机制的NutDao + * @author wendal(wendal1985@gmail.com) + * + */ +public class LazyNutDao extends NutDao { + + public void setDataSource(DataSource ds) { + super.setDataSource(ds); + this.holder = new EntityHolder(this) { + @SuppressWarnings("unchecked") + public Entity getEntity(Class classOfT) { + if (AopCallback.class.isAssignableFrom(classOfT)) + return (Entity) getEntity(classOfT.getSuperclass()); + return super.getEntity(classOfT); + } + }; + this.holder.maker = createEntityMaker(); + } + + protected EntityMaker createEntityMaker() { + return new LazyAnnotationEntityMaker(dataSource, expert, holder, this); + } + + public LazyNutDao() { + super(); + } + + public LazyNutDao(DataSource dataSource) { + super(dataSource); + } + + public LazyNutDao(DataSource dataSource, SqlManager sqlManager) { + super(dataSource, sqlManager); + } +}