架构探险-从零开始写Javaweb框架读书笔记(2)
来源:互联网 发布:seo关键词优化外包 编辑:程序博客网 时间:2024/05/22 19:52
实现Bean容器
bean容器是通过保存类与实例化的对象的映射关系。进行依赖注入(DI),又称为控制反转(IOC)
学习Java的反射
反射这个概念很美妙,反着射,我理解的意思就是不仅仅通过对象才能获取到属性,也可以根据类来设置对象的属性。
- 首先先看一下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进去的值也会被返回。
0 0
- 架构探险-从零开始写Javaweb框架读书笔记(2)
- 架构探险-从零开始写Javaweb框架读书笔记(1)
- 架构探险-从零开始写Javaweb框架读书笔记(3)
- 架构探险-从零开始写Javaweb框架读书笔记(4)
- 架构探险-从零开始写Javaweb框架读书笔记(5)
- 架构探险 从零开始写javaweb框架
- [笔记]架构探险-从零开始写JavaWeb框架-1. 之搭建轻量级mvc框架
- [笔记]架构探险-从零开始写JavaWeb框架-2.2. 之使框架具有aop特性-干货,让框架支持事务处理
- 读书杂谈-《架构探险:从零开始写Java Web框架》
- 《架构探险—从零开始写Java Web框架》读后感
- 荐书:《架构探险:从零开始写分布式服务框架》
- [笔记]架构探险-从零开始写JavaWeb框架-2.1. 之使框架具有aop特性-aop框架加载与切面运行流程分析
- 架构探险读书笔记——自己搭建轻量级javaWeb框架之MVC和IOC
- 《架构探险——从零开始写Java Web框架》 试读——感想
- 《架构探险——从零开始写Java Web框架》 试读心得
- 从零开始写javaweb框架笔记2-搭建web项目框架
- 《从零开始写Javaweb框架》知识点--配置文件读取
- 《从零开始写Javaweb框架》知识点--dispatcherServlet
- Android webView 软键盘覆盖输入框,webView页面底部显示不全
- select,epoll,poll比较(网络资源总结)
- leetcode 22. Generate Parentheses 递归
- adb出现cannot parse version string:kg01的解决方法
- Android Studio可能用到的快捷键
- 架构探险-从零开始写Javaweb框架读书笔记(2)
- “时间复杂度”的理解
- 归并排序
- 求逆元
- c++ 生成文件MD5
- Socket原理与编程基础
- xml元素类型PCDATA和CDATA的区别(DTD中)
- 字符串算法(KMP+MANACHER+EX_KMP)总结
- 决策树(七)--Boost及源码分析