架构探险-从零开始写Javaweb框架读书笔记(2)

版权声明:如果没有实践过,请不要转载,容易害人,转载请注明出处,禁止用于商业用途(http://blog.csdn.net/u013076044) https://blog.csdn.net/u013076044/article/details/52150276

实现Bean容器

bean容器是通过保存类与实例化的对象的映射关系。进行依赖注入(DI),又称为控制反转(IOC)

学习Java的反射

反射这个概念很美妙,反着射,我理解的意思就是不仅仅通过对象才能获取到属性,也可以根据类来设置对象的属性。

  1. 首先先看一下java的反射包(java.lang.reflect),使用官方的api来达到我们的目的
    (1)创建实例化对象
    (2) 为对象注入属性
    (3) 调用方法
    那么我们先写一个工具类reflect达到我们的目的
/**
 * 反射工具类
 *
 * Created by xueaohui on 2016/6/22.
 */
public final class ReflectionUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtil.class);

    /**
     * 创建实例
     */
    public static Object newInstance(Class<?> cls){
        Object instance ;
        try {
            instance = cls.newInstance();
        }catch (Exception e){
            LOGGER.error("new instance failure" , e );
            throw new RuntimeException(e);
        }
        return instance;
    }

    /**
     * 调用方法
     */
    public static Object invokeMethod(Object obj , Method method , Object... args){
        Object result ;
        try {
            method.setAccessible(true);
            result = method.invoke(obj, args);
        }catch (Exception e){
            LOGGER.error("invoke method failure" , e );
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 设置成员变量的值
     */
    public static void setField(Object obj , Field field , Object value){
        try {
        //如果设置属性为private并且不调用这个方法,会抛出IllegalAccessException 异常
            field.setAccessible(true);
            field.set(obj,value);
        } catch (IllegalAccessException e) {
            LOGGER.error("set field failure" , e );
            throw new RuntimeException(e);
        }

    }
}

根据以上方法,那么我们知道,只要我们知道了类,那么我们就知道了一切。
我们需要扫描所有我们编写的类,开发一个类加载器。

开发一个类加载器

那么我们需要以下功能
(1) 获取类加载器
(2) 获取类
(3) 加载类


/**
 * Created by xueaohui on 2016/6/22.
 */
public final class ClassUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);

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

    /**
     * 加载类
     */
    public static Class<?>loadClass(String className , boolean isInitialized){
        Class<?> cls;

        try {
            cls = Class.forName(className,isInitialized,getClassLoader());
        } catch (ClassNotFoundException e) {
            LOGGER.error("load class failure" , e);
            throw new RuntimeException(e);
        }

        return cls;
    }

    /**
     * 加载类(默认将初始化类)
     */
    public static Class<?> loadClass(String className) {
        return loadClass(className, true);
    }

    /**
     * 获取指定包下的所有类
     */
    public static Set<Class<?>> getClassSet(String packageName){
        Set<Class<?>> classSet = new HashSet<Class<?>>();

        try {
            //今天才知道的枚举类
            //Enumeration 比 Iterator 的遍历速度更快
            //因为没有fast-fail机制
            Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));

            while(urls.hasMoreElements()){
                URL url = urls.nextElement();

                if(url != null){
                    //获取环境 是文件环境 还是jar环境
                    String protocol = url.getProtocol();

                    if(protocol.equals("file")){
                        String packagePath = url.getPath().replaceAll("%20", "");
                        addClass(classSet,packagePath,packageName);
                    }else if(protocol.equals("jar")){
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();

                        if(jarURLConnection != null){
                            JarFile jarFile = jarURLConnection.getJarFile();

                            if(jarFile != null){
                                Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();

                                while (jarEntryEnumeration.hasMoreElements()){
                                    JarEntry jarEntry = jarEntryEnumeration.nextElement();
                                    String jarEntryName = jarEntry.getName();
                                    if(jarEntryName.endsWith(".class")){
                                        String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".")).replaceAll("/",".");
                                        doAddClass(classSet,className);
                                    }
                                }
                            }
                        }
                    }
                }
            }


        }catch (Exception e){
            LOGGER.error("get classSet failure" , e );
            throw new RuntimeException(e);
        }

        return classSet;
    }

    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;
                }

                addClass(classSet,subPackagePath,subPackageName);
            }
        }
    }

    private static void doAddClass(Set<Class<?>> classSet, String className) {
        Class<?> cls = loadClass(className,false);
        classSet.add(cls);
    }


}

我们开发一个类操作助手来通过获取我们编写代码的包来加载类

/**
 * Created by xueaohui on 2016/6/22.
 * 类操作助手
 */
public final class ClassHelper {

    /**
     * 定义类集合(用于存放加载的类)
     */
    private static final Set<Class<?>> CLASS_SET;

    static {
        String beanPackage = ConfigHelper.getAppBasePackage();
        CLASS_SET = ClassUtil.getClassSet(beanPackage);
    }

    /**
     * 获取包下的所有类
     */
    public static Set<Class<?>> getClassSet(){
        return CLASS_SET;
    }

    /**
     * 获取应用包下所有的Service类
     */
    public static Set<Class<?>> getServiceClassSet(){
        Set<Class<?>> set = new HashSet<Class<?>>();

        for(Class<?> cls : CLASS_SET){
            if(cls.isAnnotationPresent(Service.class)){
                set.add(cls);
            }
        }

        return set;
    }

    /**
     * 获取应用包下所有的Controller类
     */
    public static Set<Class<?>> getControllerClassSet(){
        Set<Class<?>> set = new HashSet<Class<?>>();

        for(Class<?> cls : CLASS_SET){
            if(cls.isAnnotationPresent(Controller.class)){
                set.add(cls);
            }
        }

        return set;
    }

    /**
     * 获取包下所有的bean 包括 service 和 controller 等
     */
    public static Set<Class<?>> getBeanClassSet(){
        Set<Class<?>> beanClassSet = new HashSet<Class<?>>();
        beanClassSet.addAll(getControllerClassSet());
        beanClassSet.addAll(getServiceClassSet());
        return beanClassSet;
    }

    /**
     * 获取应用包名下某父类(或接口)的所有接口(或实现类)
     */
    public static Set<Class<?>> getClassSetBySuper(Class<?> superClass){
        Set<Class<?>> classSet = new HashSet<Class<?>>();

        for(Class<?> cls : CLASS_SET){
            if(superClass.isAssignableFrom(cls)&&!superClass.equals(cls)){
                classSet.add(cls);
            }
        }

        return classSet;
    }

    /**
     * 获取应用包名下带有某注解的类
     */
    public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass){
        Set<Class<?>> classSet = new HashSet<Class<?>>();

        for(Class<?> cls : CLASS_SET){
            if(cls.isAnnotationPresent(annotationClass)){
                classSet.add(cls);
            }
        }

        return classSet;
    }
}

以上可知我们可以获取到所有的class
那么我们就要开发这个bean容器,实现类-实例对象的映射
只需用Map容器即可实现

/**
 * Bean 助手类
 * Created by xueaohui on 2016/6/22.
 */
public final class BeanHelper {

    /**
     * 定义Bean映射 (用于存放 Bean 类 与 Bean 实例的映射关系)
     */

    private static final Map<Class<?>,Object>BEAN_MAP = new HashMap<Class<?>, Object>();

    static {
        Set<Class<?>> classSet = ClassHelper.getBeanClassSet();

        for(Class<?>beanClass : classSet){
            BEAN_MAP.put(beanClass, ReflectionUtil.newInstance(beanClass));
        }
    }

    /**
     * 获取Bean映射
     */
    public static Map<Class<?>,Object>getBeanMap(){
        return BEAN_MAP;
    }

    /**
     * 获取Bean实例
     */
    public static <T> T getBean(Class<T> cls){
        if(!BEAN_MAP.containsKey(cls)){
            throw new RuntimeException("can not get bean by class " + cls );
        }
        return (T)BEAN_MAP.get(cls);
    }

    /**
     * 设置bean 实例
     */
    public static void setBean(Class<?> cls,Object obj){
        BEAN_MAP.put(cls,obj);
    }

}

以上我们就实现bean容器,我们实现这个容器的作用就是可以通过框架来实现管理我们的对象。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。比如controller中我设置了一个hashmap用来返回json对象,如果controller是单例的,那么每一次访问这个controller的借口时候hashmap原来put进去的值也会被返回。

展开阅读全文

没有更多推荐了,返回首页