持有者Container.java持有,所有的控制器和拦截器实例,多个拦截器构成拦截器链。
初始化控制器:非常简单,在DispatcherServlet初始化时,调用它Container.init(config),init方法里查找所有class文件,有Mapping注解的方法,校验后,即为控制器。
初始化拦截器:同上。Mapping注解有2个参数url,cmi,其中cmi为自定义拦截器(cmi为c:controller,m:me,i:interceptor)。Container.java代码如下:
package cn.eternal.container; import java.io.File; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import cn.eternal.annotation.Mapping; import cn.eternal.config.Config; import cn.eternal.config.ConfigException; import cn.eternal.handler.InstanceHandler; import cn.eternal.handler.MappingHandler; import cn.eternal.interceptor.EmptyInterceptor; import cn.eternal.interceptor.Interceptor; import cn.eternal.renderer.Renderer; import cn.eternal.util.ConverterUtil; public class Container { private static Log log = LogFactory.getLog(Container.class); public static Map<MappingHandler,Interceptor[]> interceptors = new HashMap<MappingHandler,Interceptor[]>(); public static MappingHandler[] MappingHandlers = null; public static Map<MappingHandler, InstanceHandler> mhih = new HashMap<MappingHandler, InstanceHandler>(); private static ConverterUtil converterUtil = new ConverterUtil(); public static void init(final Config config) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ initControllersAndInterceptors(config); } static void warnInvalidInstanceHandlerMethod(Method m, String string) { log.warn("Init Invalid Controller method '" + m.toGenericString() + "': " + string); } public static void initControllersAndInterceptors(Config config) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ ClassLoader cld = Thread.currentThread().getContextClassLoader(); URL resource = cld.getResource("/"); File dirs = new File(resource.getFile()); ArrayList<Class> classList = new ArrayList<Class>(); findClass(dirs,"",classList); findControllersAndInterceptors(classList,config.getInitParameter("interceptors")); MappingHandlers = mhih.keySet().toArray(new MappingHandler[mhih.size()]); Arrays.sort( MappingHandlers, new Comparator<MappingHandler>() { public int compare(MappingHandler o1, MappingHandler o2) { String u1 = o1.url; String u2 = o2.url; int n = u1.compareTo(u2); if (n==0) throw new ConfigException("Cannot mapping one url '" + u1 + "' to more than one Controller method."); return n; } } ); } private static void findClass(File dirs,String basePack,ArrayList<Class> classList) throws ClassNotFoundException { File[] childs = dirs.listFiles(); for (int i = 0; i < childs.length; i++) { String packPath =basePack+childs[i].getName()+"."; if (childs[i].isDirectory()) { findClass(childs[i],packPath,classList); } else { String className = childs[i].getName(); if (className.endsWith(".class")) { packPath=packPath.replace(".class.", ""); classList.add(Class.forName(packPath)); } } } } private static void findControllersAndInterceptors(ArrayList<Class> classLst,String inters) throws InstantiationException, IllegalAccessException, ClassNotFoundException { for (int c = 0; c < classLst.size(); c++) { Class clazz = classLst.get(c); Method mArr[] = clazz.getDeclaredMethods(); for (Method m:mArr) { if (isControllerMethod(m)) { Mapping mapping = m.getAnnotation(Mapping.class); String url = mapping.url(); MappingHandler matcher = new MappingHandler(url); if (matcher.getArgumentCount()!=m.getParameterTypes().length) { warnInvalidInstanceHandlerMethod(m, "Arguments in URL '" + url + "' does not match the arguments of method."); continue; } log.info("Init Controller "+m.toGenericString()+" Mapping url '" + url + "'."); mhih.put(matcher, new InstanceHandler(clazz.newInstance(), m)); Class cmi = mapping.cmi(); String cinters = ""; if(cmi != null && cmi != EmptyInterceptor.class){ if(inters != "" && inters != null){ cinters = ","+cmi.getName(); log.info("Init Interceptor "+cmi.getName()+" For "+m.toGenericString()+"."); } } addInterceptors(matcher,(inters+cinters).split(",")); } } } } static void addInterceptors(MappingHandler matcher,String[] inters) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Interceptor[] interArr = new Interceptor[inters.length]; for(int i=0;i<inters.length;i++){ interArr[i] = (Interceptor)(Class.forName(inters[i])).newInstance(); } interceptors.put(matcher,interArr); } static boolean isControllerMethod(Method m) { Mapping mapping = m.getAnnotation(Mapping.class); if (mapping==null) return false; if (mapping.url().length()==0) { warnInvalidInstanceHandlerMethod(m, "Url mapping cannot be empty."); return false; } if (Modifier.isStatic(m.getModifiers())) { warnInvalidInstanceHandlerMethod(m, "method is static."); return false; } Class<?>[] argTypes = m.getParameterTypes(); for (Class<?> argType : argTypes) { if (!converterUtil.canConvert(argType)) { warnInvalidInstanceHandlerMethod(m, "unsupported parameter '" + argType.getName() + "'."); return false; } } Class<?> retType = m.getReturnType(); if (retType.equals(void.class) || retType.equals(String.class) || Renderer.class.isAssignableFrom(retType) ) return true; warnInvalidInstanceHandlerMethod(m, "unsupported return type '" + retType.getName() + "'."); return false; } public static void destroy() { interceptors = null; MappingHandlers = null; mhih = null; converterUtil = null; } public static MappingHandler[] getMappingHandlers() { return MappingHandlers; } public static Map<MappingHandler, InstanceHandler> getMhih() { return mhih; } public static Interceptor[] getInterceptors(MappingHandler matcher) { return interceptors.get(matcher); } }
Mapping.java代码:
package cn.eternal.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import cn.eternal.interceptor.EmptyInterceptor; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Mapping { String url(); Class<?> cmi() default EmptyInterceptor.class; }