jfinalConfig.configInterceptor(interceptors);
@Override
public void configInterceptor(Interceptors me) {
me.add(new GlobalActionInterceptor());
}
添加全局拦截器,最终会把这里添加的拦截器存储到InterceptorManager类的singletonMap中
private void addGlobalInterceptor(boolean forAction, Interceptor... inters) {
...略
for (Interceptor inter : inters) {
singletonMap.put(inter.getClass(), inter);
}
...略
}
jfinalConfig.configHandler(handlers);
这里比较简单,直接把handler存储到了Handlers类的集合中
final public class Handlers {
private final List<Handler> handlerList = new ArrayList<Handler>();
public Handlers add(Handler handler) {
if (handler != null)
handlerList.add(handler);
return this;
}
public List<Handler> getHandlerList() {
return handlerList;
}
}
到这里,就把我们自己写MianConfig中有所有配置信息,初始化到Config中。
回到JFinal类的init()方法
boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
this.servletContext = servletContext;
this.contextPath = servletContext.getContextPath();
initPathUtil();
Config.configJFinal(jfinalConfig); // start plugin and init log factory in this method
constants = Config.getConstants();
initActionMapping();
initHandler();
initRender();
initOreillyCos();
initTokenManager();
return true;
}
继续看initActionMapping();
private void initActionMapping() {
actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());
actionMapping.buildActionMapping();
Config.getRoutes().clear();
}
创建了ActionMapping类的对象,并把刚才初始化到Config中的路径信息和拦截器传递到了ActionMapping对象中,并调用了actionMapping.buildActionMapping();方法。
void buildActionMapping() {
mapping.clear();
Set<String> excludedMethodName =buildExcludedMethodName();
InterceptorManager interMan = InterceptorManager.me();
for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) {
Class<? extends Controller> controllerClass = entry.getValue();
Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass);
boolean sonOfController = (controllerClass.getSuperclass() == Controller.class);
Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());
for (Method method : methods) {
String methodName = method.getName();
if (excludedMethodName.contains(methodName) method.getParameterTypes().length != 0)
continue ;
if (sonOfController && !Modifier.isPublic(method.getModifiers()))
continue ;
Interceptor[] actionInters = interMan.buildControllerActionInterceptor(controllerInters, controllerClass, method);
String controllerKey = entry.getKey();
ActionKey ak = method.getAnnotation(ActionKey.class);
String actionKey;
if (ak != null) {
actionKey = ak.value().trim();
if ("".equals(actionKey))
throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");
if (!actionKey.startsWith(SLASH))actionKey = SLASH + actionKey;
}
else if (methodName.equals("index")) {
actionKey = controllerKey;
}else {
actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
}
Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
if (mapping.put(actionKey, action) != null)
throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
}
}
Action action = mapping.get("/");
if (action != null)
mapping.put("", action);
}
方法一开始先是调用了buildExcludedMethodName()方法返回一个Set集合
private Set<String> buildExcludedMethodName() {
Set<String> excludedMethodName = new HashSet<String>();
Method[] methods = Controller.class.getMethods();
for (Method m : methods) {
if (m.getParameterTypes().length == 0)
excludedMethodName.add(m.getName());
}
return excludedMethodName;
}
其实就是将Controller类中不带参数的方法名获取处理存储到Set集合中,便于区分用户自己在Controller中编写的Action方法。紧接着获取了InterceptorManager拦截器Manager的实例。然后对从Config中传递进来的Routes中的map集合进行了遍历,依次取出Controller的Class,然后通过调用InterceptorManager.createControllerInterceptor()方法,取出注解在Controller类的拦截器信息,并存储到InterceptorManager中
Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass);
public Interceptor[] createControllerInterceptor(Class<? extends Controller> controllerClass) {
return createInterceptor(controllerClass.getAnnotation(Before.class));
}
接着看
boolean sonOfController = (controllerClass.getSuperclass() == Controller.class);
Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());
这里获取到了Controller中的所有Action方法,通过判断是否是Controller的子类,来解决我们自己编写的Controller的继承问题
// 遍历methods
for (Method method : methods) {
String methodName = method.getName();
// 去除Controller父类中的方法和权限不为public的方法
if (excludedMethodName.contains(methodName) method.getParameterTypes().length != 0)
continue ;
if (sonOfController && !Modifier.isPublic(method.getModifiers()))
continue ;
// 获取method的注解拦截器,并添加全局拦截器和类拦截器并返回
Interceptor[] actionInters = interMan.buildControllerActionInterceptor(controllerInters, controllerClass, method);
// 获取Controller的路径信息,判断是否配置有ActionKey,对Action的路径 “/” 进行处理,单独处理 index 方法
String controllerKey = entry.getKey();
ActionKey ak = method.getAnnotation(ActionKey.class);
String actionKey;
if (ak != null) {
actionKey = ak.value().trim();
if ("".equals(actionKey))
throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");
if (!actionKey.startsWith(SLASH))
actionKey = SLASH + actionKey;
}
else if (methodName.equals("index")) {
actionKey = controllerKey;
}
else {
actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
}
// 最终生成一个Action实例
// controllerKey: 请求Controller根路径
// actionKey:请求method的路径
// controllerClass:Controller的Class
// actionInters:拦截器
Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
if (mapping.put(actionKey, action) != null)
throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
}
看个具体的实例
public final class AppRoute extends Routes {
@Override
public void config() {
//这里的"/user" 就是controllerKey
this.add("/user", UserAction.class);
}
}
public class UserAction extends Controller {
// 这里的login 就是actionKey
public void login(){
}
}
这里如果要访问UserAction的login方法,路径则为localhost:port/user/login
Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
if (mapping.put(actionKey, action) != null)
throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
在创建好Action之后,把Action存储到了一个map集合之中,如果集合中已经存在这个Action,则抛出异常