package org.nutz.dao.impl.ext; import java.lang.reflect.Method; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.WeakHashMap; import javax.sql.DataSource; import org.nutz.aop.ClassAgent; 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.lang.born.BornContext; import org.nutz.lang.born.Borns; 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; public LazyAnnotationEntityMaker(DataSource datasource, JdbcExpert expert, EntityHolder holder, Dao dao) { super(datasource, expert, holder); this.dao = dao; } protected <T> NutEntity<T> _createNutEntity(Class<T> type) { return new LazyNutEntity<T>(type); } @Override public <T> Entity<T> make(Class<T> type) { LazyNutEntity<T> en = (LazyNutEntity<T>) super.make(type); en.init(); return en; } class LazyNutEntity<T> extends NutEntity<T> { public LazyNutEntity(Class<T> type) { super(type); } @SuppressWarnings({"rawtypes", "unchecked"}) public void init() { List<LinkField> lfs = new ArrayList<LinkField>(); lfs.addAll(ones.getAll()); lfs.addAll(manys.getAll()); lfs.addAll(manymanys.getAll()); if (lfs.isEmpty()) return; if (log.isDebugEnabled()) log.debug("Found links , enable lazy!! -->" + type); Mirror<T> mirror = Mirror.me(type); List<InterceptorPair> interceptorPairs = new ArrayList<InterceptorPair>(); // 准备拦截器 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.upperFirst(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(DefaultClassDefiner.defaultOne(), type); // 检查对象的创建方法 BornContext<T> bc = Borns.evalByArgTypes(type, ResultSet.class); if (null == bc) this.bornByDefault = Mirror.me(lazyClass) .getBorningByArgTypes(); else this.bornByRS = bc.getBorning(); } } class LazyMethodInterceptor implements MethodInterceptor { private WeakHashMap<Object, LazyStatus> status = new WeakHashMap<Object, LazyAnnotationEntityMaker.LazyStatus>(); 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 { LazyStatus stat = status.get(chain.getCallingObj()); if (stat == null) { if (chain.getCallingMethod() != setter) dao.fetchLinks(chain.getCallingObj(), fieldName);// 这里会触发setter被调用 status.put(chain.getCallingObj(), LazyStatus.NO_NEED); // 如果setter被调用,那么也就不再需要懒加载了 } chain.doChain(); } } enum LazyStatus { CAN_FETCH, FETCHED, NO_NEED } }