Java tutorial
/* * BJAF - Beetle J2EE Application Framework * J2EE?? * ?2003-2015 (www.beetlesoft.net) * * ?? *<http://www.apache.org/licenses/LICENSE-2.0> *?????? * * ?? * <yuhaodong@gmail.com/>. */ package com.beetle.framework.resource.dic; import java.io.File; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; import com.beetle.framework.AppRuntimeException; import com.beetle.framework.log.AppLogger; import com.beetle.framework.resource.dic.aop.AopInterceptor; import com.beetle.framework.resource.dic.aop.InnerHandler; import com.beetle.framework.resource.dic.def.Aop; import com.beetle.framework.resource.dic.def.AsyncMethodCallback; import com.beetle.framework.resource.dic.def.DaoField; import com.beetle.framework.resource.dic.def.ServiceField; import com.beetle.framework.resource.dic.def.ServiceTransaction; import com.beetle.framework.util.ClassUtil; /** * ?? * * @author HenryYu * */ public class ReleBinder { private final List<BeanVO> beanVoList; private static AppLogger logger = AppLogger.getInstance(ReleBinder.class); private final static Map<String, Object> DI_AOP_PROXY_CACHE = new ConcurrentHashMap<String, Object>(); private final static Set<String> DAO_CHECK = new java.util.HashSet<String>(); public ReleBinder() { super(); this.beanVoList = new ArrayList<BeanVO>(); } public static Object getProxyFromCache(String key) { return DI_AOP_PROXY_CACHE.get(key); } public List<BeanVO> getBeanVoList() { return beanVoList; } public static class FieldVO { private String name; private String ref; public FieldVO(String name, String ref) { this.name = name; this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } @Override public String toString() { return "PropertyVO [name=" + name + ", ref=" + ref + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((ref == null) ? 0 : ref.hashCode()); return result; } } public static class BeanVO { private static final Map<Method, ServiceTransaction.Manner> trans = new HashMap<Method, ServiceTransaction.Manner>( 1334); private static final Map<Method, Integer> async = new HashMap<Method, Integer>(); public static Map<Method, ServiceTransaction.Manner> getTrans() { return trans; } public static Map<Method, Integer> getAsync() { return async; } public static boolean existInTrans(Method key) { return trans.containsKey(key); } public static boolean existInAsync(Method key) { return async.containsKey(key); } public static int getFromAsync(Method key) { return async.get(key); } public static ServiceTransaction.Manner getFromTrans(Method key) { return trans.get(key); } public BeanVO(Class<?> iface, Class<?> imp, boolean single, int flag) { super(); this.iface = iface; this.imp = imp; this.single = single; this.flag = flag; this.properties = new ArrayList<FieldVO>(); } public BeanVO(String aopId, AopInterceptor interceptor) { super(); this.aopId = aopId; this.interceptor = interceptor; this.properties = new ArrayList<FieldVO>(); } private String aopId; private AopInterceptor interceptor; private Method aopMethod; private Class<?> iface; private Class<?> imp; private boolean single; private int flag; private final List<FieldVO> properties;// for inject // private Method transMethod; // private ServiceTransaction.Manner transManner; public Method getAopMethod() { return aopMethod; } public void setAopMethod(Method aopMethod) { this.aopMethod = aopMethod; } public List<FieldVO> getProperties() { return properties; } public String getAopId() { return aopId; } public AopInterceptor getInterceptor() { return interceptor; } @SuppressWarnings("rawtypes") public Class getIface() { return iface; } public Class<?> getImp() { return imp; } public int getFlag() { return flag; } public boolean isSingle() { return single; } @Override public String toString() { return "BeanVO [aopId=" + aopId + ", interceptor=" + interceptor + ", aopMethod=" + aopMethod + ", iface=" + iface + ", imp=" + imp + ", single=" + single + ", flag=" + flag + ", properties=" + properties + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((aopId == null) ? 0 : aopId.hashCode()); result = prime * result + ((aopMethod == null) ? 0 : aopMethod.hashCode()); result = prime * result + flag; result = prime * result + ((iface == null) ? 0 : iface.hashCode()); result = prime * result + ((imp == null) ? 0 : imp.hashCode()); result = prime * result + ((interceptor == null) ? 0 : interceptor.hashCode()); result = prime * result + ((properties == null) ? 0 : properties.hashCode()); result = prime * result + (single ? 1231 : 1237); return result; } } protected void bindAopInterceptor(String aopid, AopInterceptor interceptor) { BeanVO bvo = new BeanVO(aopid, interceptor); if (!beanVoList.contains(bvo)) { beanVoList.add(bvo); } } /** * * * @param clazz * * @param singleton * ??true--? */ public void bind(Class<?> clazz, boolean singleton) { BeanVO bvo = new BeanVO(null, clazz, singleton, 1); if (!beanVoList.contains(bvo)) { beanVoList.add(bvo); } } /** * ?--- * * @param interfaceClazz * ? * @param implementClazz * * @param singleton */ public void bind(Class<?> interfaceClazz, Class<?> implementClazz, boolean singleton) { if (!interfaceClazz.isAssignableFrom(implementClazz)) { throw new AppRuntimeException("err:" + interfaceClazz.getSimpleName() + " must be " + implementClazz.getSimpleName() + "'s father or interface!"); } BeanVO bvo = new BeanVO(interfaceClazz, implementClazz, singleton, 2); if (!beanVoList.contains(bvo)) { beanVoList.add(bvo); } // beanVoList.add(new BeanVO(interfaceClazz, implementClazz, singleton, // 2)); } /** * ? * * @param xmlFileInputStream * --?? */ public void bindFromConfig(InputStream xmlFileInputStream) { SAXReader reader = new SAXReader(); Document doc = null; try { doc = reader.read(xmlFileInputStream); gendoc(doc); // bindProperties(); } catch (Exception de) { throw new AppRuntimeException(de); } finally { if (doc != null) { doc.clearContent(); doc = null; } reader = null; } } /** * ? XML?<br> * * <pre> * <binder> * <!-- * interface-????? * implement-??????interface * singleton-??implement?true * --> * <item interface= "com.beetle.framework.util.pattern.di.IService" implement= "com.beetle.framework.util.pattern.di.IServiceImp" singleton="true"/> * </binder> * </pre> * * <br> * * @param f * --? */ public void bindFromConfig(File f) { SAXReader reader = new SAXReader(); Document doc = null; try { doc = reader.read(f); gendoc(doc); // bindProperties(); } catch (Exception de) { throw new AppRuntimeException(de); } finally { if (doc != null) { doc.clearContent(); doc = null; } reader = null; } } private void gendoc(Document doc) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Node node = doc.selectSingleNode("binder"); if (node != null) { Iterator<?> it = node.selectNodes("item").iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String aopid = e.valueOf("@aopid"); if (aopid != null && aopid.trim().length() > 0) { String inerceptor = e.valueOf("@interceptor"); this.bindAopInterceptor(aopid, (AopInterceptor) Class.forName(inerceptor.trim()).newInstance()); } else { dealInject(e); } } } } private void dealInject(Element e) throws ClassNotFoundException { String face = e.valueOf("@interface"); String imp = e.valueOf("@implement"); String singleton = e.valueOf("@singleton"); boolean sf = false; if (singleton == null || singleton.trim().length() == 0) { sf = true; } else { if (singleton.trim().equalsIgnoreCase("true")) { sf = true; } } if (imp == null || imp.trim().length() == 0) { throw new DependencyInjectionException("config content formate err,implement can't be null"); } if (face == null || face.trim().length() == 0) { bind(Class.forName(imp.trim()), sf); } else { boolean f = face.toLowerCase().matches(".*\\.dao\\..*"); if (f) { DAO_CHECK.add(face); } if (Class.forName(face.trim()).isAssignableFrom(Class.forName(imp.trim()))) { bind(Class.forName(face.trim()), Class.forName(imp.trim()), sf); } else { throw new DependencyInjectionException("not support this case!"); } } } void bindProperties() { logger.debug("beanVoList size:{}", beanVoList.size()); logger.debug("beanVoList:{}", beanVoList); for (BeanVO vo : beanVoList) { setBeanVoProperty(vo); } } private void setBeanVoProperty(BeanVO bvo) { logger.debug("bvo:{}", bvo); Class<?> imp = bvo.getImp(); if (imp == null) {// aop case return; } // imp????????? //Field[] fields = imp.getDeclaredFields(); Field[] fields = ClassUtil.getAllFields(imp); if (fields != null && fields.length > 0) { for (Field f : fields) { if (f.isAnnotationPresent(DaoField.class)) { if (DAO_CHECK.contains(bvo.getIface().getName())) { throw new DependencyInjectionException("DAO[" + imp.getName() + "] cannot use daoField annotation, do not conform to the programming paradigm!"); } FieldVO pvo = new FieldVO(f.getName(), f.getType().getName()); bvo.getProperties().add(pvo); logger.debug("pvo:{}", pvo); } else if (f.isAnnotationPresent(ServiceField.class)) {// ??? throw new DependencyInjectionException("The [" + imp.getName() + "] cannot use serviceField annotation, do not conform to the programming paradigm!"); } } } Method[] methods = imp.getDeclaredMethods(); for (Method m : methods) { if (m.isAnnotationPresent(Aop.class)) { dealAop(bvo, m); } if (m.isAnnotationPresent(ServiceTransaction.class)) { if (DAO_CHECK.contains(bvo.getIface().getName())) { throw new DependencyInjectionException("DAO[" + imp.getName() + "] cannot use transaction annotation, do not conform to the programming paradigm!"); } dealTrans(bvo, m); } // async call Class<?> pts[] = m.getParameterTypes(); for (int i = 0; i < pts.length; i++) { if (pts[i].isAssignableFrom(AsyncMethodCallback.class)) { dealAsyncCall(bvo, m, i); break; } } } } private void dealAsyncCall(BeanVO bvo, Method m, int pos) { initProxyAndCache(bvo); String f2 = ClassUtil.genMethodKey(m); Method[] fms = bvo.getIface().getDeclaredMethods(); for (Method fm : fms) { String f1 = ClassUtil.genMethodKey(fm); if (f1.equals(f2)) { // bvo.getTrans().put(fm, manner); BeanVO.getAsync().put(fm, pos); break; } } } private void dealTrans(BeanVO bvo, Method m) { ServiceTransaction.Manner manner = m.getAnnotation(ServiceTransaction.class).manner(); initProxyAndCache(bvo); String f2 = ClassUtil.genMethodKey(m); Method[] fms = bvo.getIface().getDeclaredMethods(); for (Method fm : fms) { String f1 = ClassUtil.genMethodKey(fm); if (f1.equals(f2)) { // bvo.getTrans().put(fm, manner); BeanVO.getTrans().put(fm, manner); break; } } } private void dealAop(BeanVO bvo, Method m) { String aopId_m = m.getAnnotation(Aop.class).id(); if (aopId_m == null || aopId_m.length() == 0) { throw new DependencyInjectionException( logger.strFormat("Initialization error of AOP,the method[{}]'s aop id must be setted!", m)); } initProxyAndCache(bvo); Method[] fms = bvo.getIface().getDeclaredMethods(); String f2 = ClassUtil.genMethodKey(m); for (Method fm : fms) { String f1 = ClassUtil.genMethodKey(fm); if (f1.equals(f2)) { matchAopMethod(fm, aopId_m); break; } } } private void initProxyAndCache(BeanVO bvo) { try { if (!DI_AOP_PROXY_CACHE.containsKey(bvo.getIface().getName())) { Object proxy = Proxy.newProxyInstance(bvo.getIface().getClassLoader(), new Class<?>[] { bvo.getIface() }, new InnerHandler(bvo.getIface())); DI_AOP_PROXY_CACHE.put(bvo.getIface().getName(), proxy); // logger.debug("bind proxy:{},bvo:{}", proxy, bvo); } } catch (Exception e) { throw new DependencyInjectionException("Initialization error of AOP", e); } } private void matchAopMethod(Method m, String aopId_m) { for (BeanVO votmp : beanVoList) { String aid = votmp.getAopId(); if (aid == null) { continue; } if (aid.equals(aopId_m)) { votmp.setAopMethod(m); break; } } } }