package org.nutz.ioc.loader.annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import org.nutz.castor.Castors; import org.nutz.ioc.IocException; import org.nutz.ioc.IocLoader; import org.nutz.ioc.IocLoading; import org.nutz.ioc.ObjectLoadException; import org.nutz.ioc.annotation.InjectName; import org.nutz.ioc.meta.IocEventSet; import org.nutz.ioc.meta.IocField; import org.nutz.ioc.meta.IocObject; import org.nutz.ioc.meta.IocValue; import org.nutz.json.Json; import org.nutz.lang.Lang; import org.nutz.lang.Mirror; import org.nutz.lang.Strings; import org.nutz.log.Log; import org.nutz.log.Logs; import org.nutz.resource.Scans; /** * 基于注解的Ioc配置 * * @author wendal(wendal1985@gmail.com) * */ public class AnnotationIocLoader implements IocLoader { private static final Log log = Logs.get(); private HashMap<String, IocObject> map = new HashMap<String, IocObject>(); public AnnotationIocLoader(String... packages) { for (String packageZ : packages) for (Class<?> classZ : Scans.me().scanPackage(packageZ)) addClass(classZ); if (map.size() > 0) { if (log.isInfoEnabled()) log.infof("Scan complete ! Found %s classes in %s base-packages!\nbeans = %s", map.size(), packages.length, Castors.me().castToString(map.keySet())); } else { log.warn("NONE Annotation-Class found!! Check your configure or report a bug!! packages=" + Arrays.toString(packages)); } } private void addClass(Class<?> classZ) { if (classZ.isInterface() || classZ.isMemberClass() || classZ.isEnum() || classZ.isAnnotation() || classZ.isAnonymousClass()) return; int modify = classZ.getModifiers(); if (Modifier.isAbstract(modify) || (!Modifier.isPublic(modify))) return; IocBean iocBean = classZ.getAnnotation(IocBean.class); if (iocBean != null) { if (log.isDebugEnabled()) log.debugf("Found a Class with Ioc-Annotation : %s", classZ); // 采用 @IocBean->name String beanName = iocBean.name(); if (Strings.isBlank(beanName)) { // 否则采用 @InjectName InjectName innm = classZ.getAnnotation(InjectName.class); if (null != innm && !Strings.isBlank(innm.value())) { beanName = innm.value(); } // 大哥(姐),您都不设啊!? 那就用 simpleName 吧 else { beanName = Strings.lowerFirst(classZ.getSimpleName()); } } if (map.containsKey(beanName)) throw Lang.makeThrow(IocException.class, "Duplicate beanName=%s, by %s !! Have been define by %s !!", beanName, classZ, map.get(beanName).getClass()); IocObject iocObject = new IocObject(); iocObject.setType(classZ); map.put(beanName, iocObject); iocObject.setSingleton(iocBean.singleton()); if (!Strings.isBlank(iocBean.scope())) iocObject.setScope(iocBean.scope()); // 看看构造函数都需要什么函数 String[] args = iocBean.args(); // if (null == args || args.length == 0) // args = iocBean.param(); if (null != args && args.length > 0) for (String value : args) iocObject.addArg(convert(value)); // 设置Events IocEventSet eventSet = new IocEventSet(); iocObject.setEvents(eventSet); if (!Strings.isBlank(iocBean.create())) eventSet.setCreate(iocBean.create().trim().intern()); if (!Strings.isBlank(iocBean.depose())) eventSet.setDepose(iocBean.depose().trim().intern()); if (!Strings.isBlank(iocBean.fetch())) eventSet.setFetch(iocBean.fetch().trim().intern()); // 处理字段(以@Inject方式,位于字段) List<String> fieldList = new ArrayList<String>(); Mirror<?> mirror = Mirror.me(classZ); Field[] fields = mirror.getFields(Inject.class); for (Field field : fields) { Inject inject = field.getAnnotation(Inject.class); // 无需检查,因为字段名是唯一的 // if(fieldList.contains(field.getName())) // throw duplicateField(classZ,field.getName()); IocField iocField = new IocField(); iocField.setName(field.getName()); IocValue iocValue; if (Strings.isBlank(inject.value())) { iocValue = new IocValue(); iocValue.setType(IocValue.TYPE_REFER); iocValue.setValue(field.getName()); } else iocValue = convert(inject.value()); iocField.setValue(iocValue); iocObject.addField(iocField); fieldList.add(iocField.getName()); } // 处理字段(以@Inject方式,位于set方法) Method[] methods; try { methods = classZ.getMethods(); } catch (Exception e) { // 如果获取失败,就忽略之 log.infof("Fail to call getMethods() in Class=%s, miss class or Security Limit, ignore it", classZ, e); methods = new Method[0]; } catch (NoClassDefFoundError e) { log.infof("Fail to call getMethods() in Class=%s, miss class or Security Limit, ignore it", classZ, e); methods = new Method[0]; } for (Method method : methods) { Inject inject = method.getAnnotation(Inject.class); if (inject == null) continue; // 过滤特殊方法 int m = method.getModifiers(); if (Modifier.isAbstract(m) || (!Modifier.isPublic(m)) || Modifier.isStatic(m)) continue; String methodName = method.getName(); if (methodName.startsWith("set") && methodName.length() > 3 && method.getParameterTypes().length == 1) { IocField iocField = new IocField(); iocField.setName(Strings.lowerFirst(methodName.substring(3))); if (fieldList.contains(iocField.getName())) throw duplicateField(classZ, iocField.getName()); IocValue iocValue; if (Strings.isBlank(inject.value())) { iocValue = new IocValue(); iocValue.setType(IocValue.TYPE_REFER); iocValue.setValue(Strings.lowerFirst(methodName.substring(3))); } else iocValue = convert(inject.value()); iocField.setValue(iocValue); iocObject.addField(iocField); fieldList.add(iocField.getName()); } } // 处理字段(以@IocBean.field方式) String[] flds = iocBean.fields(); if (flds != null && flds.length > 0) { for (String fieldInfo : flds) { if (fieldList.contains(fieldInfo)) throw duplicateField(classZ, fieldInfo); IocField iocField = new IocField(); if (fieldInfo.contains(":")) { // dao:jndi:dataSource/jdbc形式 String[] datas = fieldInfo.split(":", 2); // 完整形式, 与@Inject完全一致了 iocField.setName(datas[0]); iocField.setValue(convert(datas[1])); iocObject.addField(iocField); } else { // 基本形式, 引用与自身同名的bean iocField.setName(fieldInfo); IocValue iocValue = new IocValue(); iocValue.setType(IocValue.TYPE_REFER); iocValue.setValue(fieldInfo); iocField.setValue(iocValue); iocObject.addField(iocField); } fieldList.add(iocField.getName()); } } // 处理工厂方法 if (!Strings.isBlank(iocBean.factory())) { iocObject.setFactory(beanName); } } else { // 这里只是检查一下@Inject,要避免抛出异常. try { if (log.isWarnEnabled()) { Field[] fields = classZ.getDeclaredFields(); for (Field field : fields) if (field.getAnnotation(Inject.class) != null) { log.warnf("class(%s) don't has @IocBean, but field(%s) has @Inject! Miss @IocBean ??", classZ.getName(), field.getName()); break; } } } catch (Exception e) { // 无需处理. } } } protected IocValue convert(String value) { IocValue iocValue = new IocValue(); if (value.contains(":")) { iocValue.setType(value.substring(0, value.indexOf(':'))); iocValue.setValue(value.substring(value.indexOf(':') + 1)); } else { iocValue.setValue(value); // TODO 是否应该改为默认refer呢? } return iocValue; } public String[] getName() { return map.keySet().toArray(new String[map.size()]); } public boolean has(String name) { return map.containsKey(name); } public IocObject load(IocLoading loading, String name) throws ObjectLoadException { if (has(name)) return map.get(name); throw new ObjectLoadException("Object '" + name + "' without define!"); } private static final IocException duplicateField(Class<?> classZ, String name) { return Lang.makeThrow(IocException.class, "Duplicate filed defined! Class=%s,FileName=%s", classZ, name); } public String toString() { return "/*AnnotationIocLoader*/\n" + Json.toJson(map); } }