《架构探险》第三章 项目核心实现

一、概述
  本章讲解了一个mvc框架的核心部分,大致分为9个部分
  1.开发环境:pom.xml文件
  2.配置文件:smart.properties(不属于框架,在实际的web应用中定义)
  3.加载配置项:  (interface) ConfigConstant
                            (final class) ConfigHelper
  4.类加载器: (final class) ClassUtil
                       (@Interface) ControllerServiceActionInject
                       (final class) ClassHelper
  5.Bean容器:(final class) ReflectionUtil
                        (final class) BeanHelper
  6.依赖注入:    (final class) IocHelper
  7.加载Controller:(class) Request、Handler
            (final class) ControllerHelper
  8.初始化框架:(final class) HelperLoader
  9.请求转发器:(class) Request、Handler、Param
                          (class) DispatcherServlet extend HttpServlet
                          (final class) StreamUtil、CodeUtil、JsonUtil
 
二、框架核心的具体实现
  2.1  想要框架达成的使用效果:
 1 package cn.m4.chapter3.controller;
 2 
 3 
 4 
 5 import cn.ease4j.annotation.Action;
 6 import cn.ease4j.annotation.Controller;
 7 import cn.ease4j.annotation.Inject;
 8 import cn.ease4j.bean.Data;
 9 import cn.ease4j.bean.Param;
10 import cn.ease4j.bean.View;
11 import cn.m4.chapter3.entity.Customer;
12 import cn.m4.chapter3.service.MyService;
13 
14 import java.util.List;
15 
16 @Controller
17 public class MyController {
18 
19     @Inject
20     private MyService myService;
21 
22     @Action("get:/customer_create")
23     public Data getCustomerList(Param param){
24         List<Customer> customerList = myService.getCustomerById();
25         return new Data(customerList);
26     }
27 }
View Code

  2.2  框架核心的具体搭建

    2.2.1  第一步、添加一个Java web框架的基本依赖。
    具体步骤是:在IDEA中新建一个Maven工程,在pom文件中添加如下10个基本依赖:Servlet、JSP、JSTL、JUNIT、SLF4J、MySQL、JSON、Apache CommonsLand、Apache Commons Collections、Apache Commons DBUtils、dbcp
     
<dependencies>
        <!--01 Servlet依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!--02 JSP依赖-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>
        <!--03 JSTL依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>runtime</scope>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!--04 SLF4J-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <!--05 mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
            <scope>runtime</scope>
        </dependency>
        <!--06 Json-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.4.4</version>
        </dependency>
        <!--添加两个Apache Commons依赖,用于提供常用工具类-->
        <!--07 Apach Commons Lang-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--08 Apache Commons Collections-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.0</version>
        </dependency>

        <!--09 Apache Commons DBUtils-->
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.6</version>
        </dependency>

        <!--10 数据库连接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
View Code

    2.2.2  第二步、提供获取并处理框架配置的工具类:ConfigConstant、ConfigHelper。

    ConfigConstant是一个存放.properties配置文件中常量名称的接口;
    ConfigHelper则是调用第二章中的PropUtil工具类去读取配置。
package cn.ease4j.constant;

/**
 * 存放配置常量名称
 * @author Zephyr
 */
public interface ConfigConstant {
    //配置文件名常量
    String CONFIG_FILE = "ease.properties";
    //数据库连接常量
    String JDBC_DRIVER = "ease.framework.jdbc.driver";
    String JDBC_URL = "ease.framework.jdbc.url";
    String JDBC_USERNAME = "ease.framework.jdbc.username";
    String JDBC_PASSWORD = "ease.framework.jdbc.password";

    //各文件资源路径
    String APP_BASE_PACKAGE = "ease.framework.app.base_package";
    String APP_JSP_PATH = "ease.framework.app.jsp_path";
    String APP_ASSET_PATH = "ease.framework.app.asset_path";
}
View Code
/**
 * 提取配置的助手类
 * @author Zephyr
 */
public final class ConfigHelper {

    private static final Properties CONFIG_PROPS =
            PropUtil.loadProps(ConfigConstant.CONFIG_FILE);

    /**
     * 获取jdbc驱动
     * @return
     */
    public static String getJdbcDriver(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.JDBC_DRIVER);
    }

    /**
     * 获取jdbc URL
     * @return
     */
    public static String getJdbcUrl(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.JDBC_URL);
    }

    /**
     * 获取jdbc用户名
     * @return
     */
    public static String getJdbcUsername(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.JDBC_USERNAME);
    }

    /**
     * 获取jdbc密码
     * @return
     */
    public static String getJdbcPassword(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.JDBC_PASSWORD);
    }

    /**
     * 获取应用的基本包路径
     * @return
     */
    public static String getAppBasePackage(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.APP_BASE_PACKAGE);
    }

    /**
     * 获取应用jsp路径(含默认值)
     * @return
     */
    public static String getAppJspPath(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.APP_JSP_PATH,"/WEB-INF/view/");
    }

    /**
     * 获取静态资源的路径(含默认值)
     * @return
     */
    public static String getAppAssetPath(){
        return PropUtil.getString(CONFIG_PROPS,ConfigConstant.APP_ASSET_PATH,"/asset/");
    }


}
View Code
/**
 * 属性文件工具类
 * @author Zephyr
 */
public class PropUtil {
    //获取日志对象
    public static final Logger LOGGER= LoggerFactory.getLogger(PropUtil.class);

    /**
     * 加载配置文件
     * @param fileName
     * @return
     */
    public static Properties loadProps(String fileName){
        Properties props=null;
        InputStream is=null;
        try {
            is=Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
            if(null==is){
                throw new FileNotFoundException(fileName+" is not found");
            }
            props=new Properties();
            props.load(is);
        }catch (IOException e){
            LOGGER.error("load properties file failure",e);
        }finally {
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    LOGGER.error("close inputstream failure",e);
                }
            }
        }
        return props;
    }

    /**
     * 获取字符型属性,指定默认值
     * @param prop
     * @param key
     * @param defaultValue
     * @return
     */
    public static String getString(Properties prop, String key,String defaultValue){
        String value=defaultValue;
        if(prop.containsKey(key)){
            value=prop.getProperty(key);
        }
        return value;
    }

    /**
     * 获取字符型属性,默认值为空
     * @param prop
     * @param key
     * @return
     */
    public static String getString(Properties prop, String key){
        return getString(prop,key,"");
    }

    /**
     * 获取整型属性,指定默认值
     * @param prop
     * @param key
     * @param defaultValue
     * @return
     */
    public static Integer getInt(Properties prop,String key,Integer defaultValue){
        Integer value = defaultValue;
        if(prop.containsKey(key)){
            value=CastUtil.castInt(prop.getProperty(key));
        }
        return value;
    }

    /**
     * 获取整型属性,默认值0
     * @param prop
     * @param key
     * @return
     */
    public static Integer getInt(Properties prop,String key){
        return getInt(prop,key,0);
    }

    /**
     * 获取布尔型属性,指定默认值
     * @param prop
     * @param key
     * @param defaultValue
     * @return
     */
    public static Boolean getBoolean(Properties prop,String key,Boolean defaultValue){
        Boolean value=defaultValue;
        if(prop.containsKey(key)){
            value=CastUtil.castBoolean(prop.getProperty(key));
        }
        return value;
    }

    /**
     * 获取布尔型属性,默认值false
     * @param prop
     * @param key
     * @return
     */
    public static Boolean getBoolean(Properties prop,String key){
        return getBoolean(prop,key,false);
    }

}
View Code

    2.2.3  第三步、提供让框架具备类加载功能的工具类以及相关注解:ClassUtil、ClassHelper、@Controller、@Service、@Action、@Inject

    1、ClassUtil中包含三个方法:getClassLoader、loadClass、getClassSet

      getClassLoader是获取当前的类加载器,其实就一行代码:Thread.currentThread().getContextClassLoader();

      loadClass用于加载类,核心代码也只有一行,用的是Class.forName,但用的是另一种不常见的形式,public static Class<?> forName(String name,boolean initialize,ClassLoader loader);三个参数的含义分别是class名、是否初始化类(后面的使用中填false)、类加载器(直接用方法类中的getClassLoader());  

      getClassSet方法体比较长。输入参数是String packageName(类似于xx.xx.xx的形式),返回参数是Set<Class<?>>,实现的功能就是根据包名,递归获取本包以及子包中的class文件的名称以及jar包中的class文件的名称,使用工具类中的loadClass方法加载并放入Set集合并返回。并且用到了2个私有方法:addClass、doAddClass。addClass用于递归获取当前包或子包中的class文件,并调用doAddClass方法;而doAddClass方法则用于加载类(调用loadClass方法)并将生成的类放入Set。

/**
 * 类操作的工具类
 * @author Zephyr Lai
 */
public class ClassUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);

    /**
     * 获取类加载器
     * @return
     */
    public static ClassLoader getClassLoader(){
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * 加载类(返回class对象)
     * @param className
     * @param ifInitialize 通常赋值为false
     * @return
     */
    public static Class<?> loadClass(String className,boolean ifInitialize){
        Class<?> clz = null;
        try {
            clz = Class.forName(className,ifInitialize,getClassLoader());
        } catch (ClassNotFoundException e) {
            LOGGER.error("load class failure",e);
            throw new RuntimeException(e);
        }
        return clz;
    }

    /**
     * 获取指定包下的所有类
     * @param packageName
     * @return
     */
    public static Set<Class<?>> getClassSet(String packageName){
        //用于存储类名的集合
        Set<Class<?>> classSet = new HashSet<Class<?>>();
        try {
            String path=packageName.replace(".", "/");
            ClassLoader classLoader = getClassLoader();
            Enumeration<URL> urls = getClassLoader().getResources(path);
            if(!urls.hasMoreElements()){
                System.out.println("no element !");
            }
            while(urls.hasMoreElements()){
                URL url = urls.nextElement();
                //非空校验
                if(null != url){
                    String protocol = url.getProtocol();
                    if(protocol.equals("file")){
                        String packagePath = url.getPath().replace("%20", " ");
                        addClass(classSet,packagePath,packageName);
                    }
                    else if(protocol.equals("jar")){
                        JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
                        if(null !=jarURLConnection){
                            JarFile jarFile = jarURLConnection.getJarFile();
                            if(null != jarFile){
                                Enumeration<JarEntry> jarEntries = jarFile.entries();
                                while(jarEntries.hasMoreElements()){
                                    JarEntry jarEntry = jarEntries.nextElement();
                                    String name = jarEntry.getName();
                                    if(name.endsWith(".class")){
                                        //去掉.class后缀并且将所有的"/"替换为"."
                                        String className = name.substring(0,name.lastIndexOf(".")).replaceAll("/",".");
                                        doAddClass(classSet,className);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("get class set failure",e);
        }

        return classSet;
    }

    /**
     * 递归获取包以及子包下的所有class文件,获取class名并加载
     * @param classSet
     * @param packagePath
     * @param packageName
     */
    private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {
        File[] files = new File(packagePath).listFiles(new FileFilter() {
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class") || file.isDirectory());
            }
        });
        for (File file : files) {
            String fileName = file.getName();
            if(file.isFile()){
                String className = fileName.substring(0, fileName.lastIndexOf("."));
                if(StringUtil.isNotEmpty(packageName)){
                    className=packageName+"."+className;
                }
                doAddClass(classSet,className);
            }
            else{
                //子目录
                String subPackagePath = fileName;
                if(StringUtil.isNotEmpty(packagePath)){
                    subPackagePath = packagePath + "/" + subPackagePath;
                }
                //子包
                String subPackageName = fileName;
                if(StringUtil.isNotEmpty(packageName)){
                    subPackageName=packageName+"."+subPackageName;
                }
                //递归,在子目录、子包中查找class文件
                addClass(classSet,subPackagePath,subPackageName);
            }
        }
    }

    /**
     * 仅生成class对象,不初始化实例
     * @param classSet
     * @param className
     */
    private static void doAddClass(Set<Class<?>> classSet, String className) {
        System.out.println(Arrays.toString(classSet.toArray()));
        Class<?> clz = loadClass(className, false);
        classSet.add(clz);
    }

}
View Code

    2、4个框架中需要提供的注解:@Controller、@Service、@Action、@Inject,目录结构如图

    

/**
 * 控制器注解
 * @author Zephyr Lai
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {

}
View Code
/**
 * 服务类注解
 * @author Zephyr Lai
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
}
View Code
/**
 * 依赖注入注解
 * @author Zephyr Lai
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}
View Code
/**
 * Action方法注解
 * 类似于Spring中的@RequestMapping
 * @author Zephyr Lai
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {

    /**
     * 请求类型与路径
     * 类似于Spring中的@RequestMapping(value=" ")
     * @return
     */
    String value();
}
View Code

    3、ClassHelper包括1个静态代码块以及3个公有的静态方法。

      静态代码块用于获取应用中所有的class(Set<Class<?>>形式)

      getClassSet:直接返回静态代码块中的Set

      getServiceClassSet:提取代码块中被@Service注解的class,放入新的Set并返回

      getControllerClassSet:提取代码块中被@Controller注解的class,放入新的Set并返回

      getBeanClassSet:提取代码块中被@Controller或者@Service注解的class,放入新的Set并返回(官话:获取被框架管理的Class(即:获取Bean类))

    2.2.4  第四步、提供Bean容器的相关工具类(核心功能是:实例化对象):ReflectionUtil、BeanHelper

    1、ReflectionUtil包含三个方法:方别用于类、方法、域。

      newInstance:核心代码就一行 class.newInstance();

      invokeMethod:核心代码两行 method.setAccessible(true);//设置为方法可以被反射机制调用

                  methos.invoke(obj,args);//反射执行方法

      setField:跟工具类中的invokeMethod方法很类似,核心代码两行 field.setAccessible(true); //设置为域可以被反射机制调用

                                   field.set(obj,value); //向obj这个对象中的field设置新的value

    2、BeanHelper包含1个private static final 的 Map<Class<?>,Object>、1个静态代码块、2个公有的静态方法。

      静态代码块的作用是调用ClassHelper中的getBeanClassSet();获取又框架管理的bean类,然后遍历调用ReflectionUtil中的newInstance方法初始化实例并放入map

      getBeanMap:获取完整的map

      getBean:根据键在map中获取对应的bean实例

package cn.ease4j.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 反射工具类
 * @author Zephyr Lai
 */
public class ReflectionUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtil.class);

    /**
     * 创建实例
     * @param clz
     * @return
     */
    public static <T> T getInstance(Class<T> clz){
        T instance= null;
        try {
            instance= clz.newInstance();
        } catch (Exception e) {
            LOGGER.error("get instance error",e);
            throw new RuntimeException(e);
        }
        return instance;
    }

    /**
     * 调用方法
     * @param obj
     * @param method
     * @param params
     * @return
     */
    public static Object invokeMethod(Object obj, Method method,Object... params){
        Object result ;
        try {
            //方法设置为可以被反射机制调用
            method.setAccessible(true);
            result=method.invoke(obj,params);
        } catch (Exception e) {
            LOGGER.error("method invoke failure",e);
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 设置成员变量的值
     * (将在IOCHelper中使用)
     * @param obj
     * @param field
     * @param value
     */
    public static void setField(Object obj, Field field,Object value){
        //todo
        try {
            //方法设置为可以被反射机制调用
            field.setAccessible(true);
            //为obj这个对象中的field的值设置为value
            field.set(obj,value);
        } catch (Exception e) {
            LOGGER.error("set field failure",e);
            throw new RuntimeException(e);
        }
    }

}
ReflectionUtil
 1 package cn.ease4j.helper;
 2 
 3 import cn.ease4j.util.ClassUtil;
 4 import cn.ease4j.util.ReflectionUtil;
 5 import com.fasterxml.jackson.databind.util.BeanUtil;
 6 import com.sun.corba.se.impl.ior.OldJIDLObjectKeyTemplate;
 7 import org.slf4j.Logger;
 8 import org.slf4j.LoggerFactory;
 9 
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.Set;
13 
14 /**
15  * 定义Bean映射,用于存放Bean类与Bean实例的映射关系
16  * @author Zephyr Lai
17  */
18 public class BeanHelper {
19     public static final Logger LOGGER = LoggerFactory.getLogger(BeanHelper.class);
20     /**
21      * 用于存放class--bean的键值对
22      */
23     public static final Map<Class<?>,Object> BEAN_MAP= new HashMap<Class<?>,Object>();
24 
25     /**
26      * 静态代码块用于初始化BEAN_MAP
27      * clz1 -- obj1
28      * clz2 -- obj2
29      */
30     static{
31         //获取由框架管理的bean
32         Set<Class<?>> beanSet = ClassHelper.getBeanClassSet();
33         for (Class<?> beanClass : beanSet) {
34             Object obj = ReflectionUtil.getInstance(beanClass);
35             BEAN_MAP.put(beanClass,obj);
36         }
37     }
38 
39     /**
40      * 获取整个Bean映射
41      * @return
42      */
43     public static Map<Class<?>,Object> getBeanMap(){
44         return BEAN_MAP;
45     }
46 
47     /**
48      * 根据class名称从映射中获取Bean实例
49      * @param clz
50      * @param <T>
51      * @return
52      */
53     public static <T> T getBean(Class<T> clz){
54         if(!BEAN_MAP.containsKey(clz)){
55             throw new RuntimeException("cannot get bean by class:"+clz.getName());
56         }
57         for (Map.Entry<Class<?>, Object> entry : BEAN_MAP.entrySet()) {
58             Class<?> key = entry.getKey();
59             Object value = entry.getValue();
60             System.out.println(1);
61         }
62         return (T) BEAN_MAP.get(clz);
63     }
64 }
BeanHelper

  2.2.5  第五步、实现框架的依赖注入(DI)功能(人话:实例化Bean中带@Inject注解的域,并设置到Bean实例中),相关工具类:IocHelper

    1、IocHelper的实现逻辑:通过BeanHelper获取所有的bean Map(存放的是class<-->obj),通过反射获取bean实例中所有的成员变量,然后遍历这些成员变量,查看是否带有@Inject注解,如果带有@Inject注解,则将成员变量实例化,并设置到Bean Map的Bean实例中

package cn.ease4j.helper;

import cn.ease4j.annotation.Inject;
import cn.ease4j.util.ArrayUtil;
import cn.ease4j.util.CollectionUtil;
import cn.ease4j.util.ReflectionUtil;

import java.lang.reflect.Field;
import java.util.Map;

/**
 * 依赖注入助手类
 * @author Zephyr Lai
 */
public final class IocHelper {

    static {
        //获取整个Bean映射
        Map<Class<?>, Object> beanMap = BeanHelper.getBeanMap();
        if(CollectionUtil.isNotEmpty(beanMap)){
            //Map遍历
            for (Map.Entry<Class<?>, Object> beanEntity : beanMap.entrySet()) {
                Class<?> beanClass = beanEntity.getKey();
                Object beanInstance = beanEntity.getValue();
                //获取class对象的所有域(属性)
                Field[] declaredFields = beanClass.getDeclaredFields();
                if(ArrayUtil.isNotEmpty(declaredFields)){
                    for (Field field : declaredFields) {
                        //匹配@Inject注解
                        if(field.isAnnotationPresent(Inject.class)){
                            //获取域的class对象
                            Class<?> type = field.getType();
                            //生成域的实例
                            Object fieldInstance = ReflectionUtil.getInstance(type);
                            if(null != fieldInstance){
                                //将域实例设置进bean实例
                                ReflectionUtil.setField(beanInstance,field,fieldInstance);
                            }
                        }
                    }
                }
            }
        }
    }
}
IocHelper
package cn.ease4j.util;

import org.apache.commons.lang3.ArrayUtils;

/**
 * 数组工具类
 * @author Zephyr Lai
 */
public class ArrayUtil {

    public static Boolean isNotEmpty(Object[] array){
        return ArrayUtils.isNotEmpty(array);
    }

    public static Boolean isEmpty(Object[] array){
        return ArrayUtils.isEmpty(array);
    }
}
ArrayUtil

  2.2.6  第六步、提供用于加载Controller的工具y以及相关类:Request、Handler、ControllerHelper

    1、Request是请求类,封装了请求方法(String)、请求路径(String)

    2、Handler是处理类,用于封装Action信息,包括controllerClass(Class<?>)、actionMethod(Method)

      一张图理清Request与Handler的关系:

  

    3、ControllerHelper包含一个private static final Map<Request,Hander>、1个静态代码块、1个公有的静态方法getHander

     map中存放请求与处理器之间的映射关系

     静态代码块则负责从现有的Controller Bean中封装Request与Handler的映射关系,封装到Map中并返回

        getHandler 则根据请求方法和请求路径从map中提取对应的处理器(Handler)

 1 package cn.ease4j.helper;
 2 
 3 import cn.ease4j.annotation.Action;
 4 import cn.ease4j.annotation.Inject;
 5 import cn.ease4j.bean.Handler;
 6 import cn.ease4j.bean.Request;
 7 import cn.ease4j.util.ArrayUtil;
 8 import cn.ease4j.util.CollectionUtil;
 9 import cn.ease4j.util.ReflectionUtil;
10 
11 import java.lang.reflect.Field;
12 import java.lang.reflect.Method;
13 import java.util.HashMap;
14 import java.util.Map;
15 import java.util.Set;
16 
17 /**
18  * 控制器助手类
19  * @author Zephyr Lai
20  */
21 public final class ControllerHelper {
22     //请求--处理器 映射
23     public static final Map<Request,Handler> ACTION_MAP = new HashMap<Request, Handler>();
24 
25     static{
26         //获取整个Bean映射
27         Map<Class<?>, Object> beanMap = BeanHelper.getBeanMap();
28         if(CollectionUtil.isNotEmpty(beanMap)){
29             //Map遍历
30             for (Map.Entry<Class<?>, Object> beanEntity : beanMap.entrySet()) {
31                 Class<?> beanClass = beanEntity.getKey();
32                 Object beanInstance = beanEntity.getValue();
33                 //获取class对象的所有域(属性)
34                 Field[] declaredFields = beanClass.getDeclaredFields();
35                 if(ArrayUtil.isNotEmpty(declaredFields)){
36                     for (Field field : declaredFields) {
37                         //匹配@Inject注解
38                         if(field.isAnnotationPresent(Inject.class)){
39                             //获取域的class对象
40                             Class<?> type = field.getType();
41                             //生成域的实例
42                             Object fieldInstance = ReflectionUtil.getInstance(type);
43                             if(null != fieldInstance){
44                                 //将域实例设置进bean实例
45                                 ReflectionUtil.setField(beanInstance,field,fieldInstance);
46                             }
47                         }
48                     }
49                 }
50             }
51         }
52 
53 
54         //获取所有的Controller Bean
55         Set<Class<?>> controllerSet = ClassHelper.getControllerClassSet();
56         if(null != controllerSet && controllerSet.size()>0){
57             for (Class<?> c : controllerSet) {
58                 //获取class对象中的所有方法
59                 Method[] methods = c.getDeclaredMethods();
60                 if(null != methods && methods.length>0){
61                     for (Method m : methods) {
62                         //匹配@Action注解
63                         if(m.isAnnotationPresent(Action.class)){
64                             Action action = m.getAnnotation(Action.class);
65                             String mapping = action.value();
66                             //正则匹配
67                             if(mapping.matches("\\w+:/\\w*")){
68                                 String[] arrays = mapping.split(":");
69                                 String requestMethod = arrays[0];
70                                 String requestPath = arrays[1];
71                                 Request request = new Request(requestMethod, requestPath);
72                                 Handler handler = new Handler(c, m);
73                                 //封装到 请求--处理器的映射
74                                 ACTION_MAP.put(request,handler);
75                             }
76                         }
77                     }
78                 }
79             }
80         }
81     }
82 
83     /**
84      * 根据请求方法(GET、POST),请求路径(../../..),
85      * 获取某个Hander(包括controller class以及对应的method)
86      * @param requestMethod
87      * @param requestPath
88      * @return
89      */
90     public static Handler getHandler(String requestMethod,String requestPath){
91         for (Map.Entry<Request, Handler> entity : ACTION_MAP.entrySet()) {
92             Handler value = entity.getValue();
93             Request request = entity.getKey();
94             System.out.println(value.getActionMethod()+"------------"+value.getControllerClass());
95         }
96         return ACTION_MAP.get(new Request(requestMethod,requestPath));
97     }
98 }
ControllerHelper

  2.2.7  第七步、提供初始化框架的工具类:LoaderHelper(加载ClassHelper、BeanHelper、IocHelper、ControllerHelper)

    没啥好说的,就遍历一下,调用4次ClassUtil#loadClass

 1 package cn.ease4j;
 2 
 3 import cn.ease4j.annotation.Controller;
 4 import cn.ease4j.helper.BeanHelper;
 5 import cn.ease4j.helper.ClassHelper;
 6 import cn.ease4j.helper.ControllerHelper;
 7 import cn.ease4j.helper.IocHelper;
 8 import cn.ease4j.util.ClassUtil;
 9 
10 /**
11  * 助手加载器
12  * @author Zephyr Lai
13  */
14 public class HelperLoader {
15     /**
16      * 依次加载各个助手(Helper)
17      */
18     public static void init(){
19         Class[] classList={
20                 ClassHelper.class,
21                 BeanHelper.class,
22                 IocHelper.class,
23                 ControllerHelper.class
24         };
25         for (Class clz : classList) {
26             ClassUtil.loadClass(clz.getName(),false);
27         }
28     }
29 }
HelperLoader

  2.2.8  第八步、提供框架中请求转发器DispatcherServlet(人话:就是写个框架中的Servlet)

(未完。。。)

  

 

 

 

 

  
 
 
 
 
 
 
posted @ 2017-12-31 20:29  ZephyrLai  阅读(570)  评论(0)    收藏  举报