动手编写一个IOC容器
来源:互联网 发布:c语言中变量的定义 编辑:程序博客网 时间:2024/05/21 10:41
动手编写一个IOC容器
标签(空格分隔): 未分类
- 动手编写一个IOC容器
- 什么是IOC
- IOC容器工作过程
- 编写代码
- 总结
什么是IOC
IOC(Inversion of control)控制反转,表示将原本由调用者自己实例化被调用类改成有容器来统一实例化调用类并且注入到调用者内部的过程。
以打牌为例,之前玩家需要自己摸牌,现在改成由发牌人为所有玩家发牌,这个过程就叫做“控制反转”,发牌人就是IOC容器,发牌人给玩家发牌的过程就被称为“依赖注入(Dependency Injection)”。
//Player自己负责实例化Cardpublic Class Player{ private Card myCard=new Card(); ...}//实例化在IOC容器(Dealer)中进行public Class Dealer{ private Card card=new Card(); ...}public Class Player{ @Inject private Card myCard;}
IOC容器工作过程
其实依赖注入的含义还是比较好理解的,乍一看觉得高深吧~
那么IOC容器怎么来实现依赖注入呢,这里提供一个比较简单的实现方案:
我们将所有被IOC容器管理的类称为Bean,在项目启动时需要扫描当前所有的java Bean并放入到一个BeanMap中,并且将他们实例化,BeanMap保存BeanClass和Bean对象的对应关系。然后遍历BeanMap中的Bean,逐个判断Bean的成员变量中是否有@Inject注解,如果有,就从BeanMap中取出这个成员变量类对应的对象,注入给这个Bean。
编写代码
根据上面的流程我们需要定义这几个工具类:
ClassUtil:扫描项目package下的所有Class
ClassHelper: 调用ClassUtil,并返回需要的Bean
ReflectionUtil: 返回对象实例,调用Settter方法实现注入
BeanHelper: 初始化BeanMap
代码参考《架构探险》一书
*ClassUtil:
需要通过ClassLoader获得项目的所有资源,分别查找文件和jar包中的类*
public static Set<Class<?>> getClassSet(String packageName) { Set<Class<?>> classSet = new HashSet<Class<?>>(); try { Enumeration<URL> urls = getClassLoader().getResources( packageName.replace(".", "/")); while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (url != null) { String protocol = url.getProtocol(); if (protocol.equals("file")) { String packagePath = url.getPath().replaceAll("%20", " "); addClassFromFile(classSet, packagePath, packageName); } else if (protocol.equals("jar")) { addClassFromJar(classSet, url); } } } } catch (Exception e) { log.error("get class set failed", e); throw new RuntimeException(e); } return classSet; }
*BeanHelper:
在初始化时立即将所有bean实例化,放入BeanMap中*
private static final Map<Class<?>,Object> BEAN_MAP=new HashMap<Class<?>, Object>(); static { Set<Class<?>> beanClass=ClassHelper.getBeanClassSet(); for(Class<?> cls:beanClass){ Object obj=ReflectionUtil.getInstance(cls); BEAN_MAP.put(cls,obj); } }
之后就可以在IOCHelper中实现依赖注入了。
public class IOCHelper { static{ Map<Class<?>,Object> beanMap=BeanHelper.getBeanMap(); if(!CollectionsUtil.isEmpty(beanMap)){ for(Map.Entry<Class<?>,Object> beanEntry:beanMap.entrySet()){ //实例化对象由容器统一管理 Class<?> beanClass=beanEntry.getKey(); Object beanInstance=beanEntry.getValue(); Field[] fields=beanClass.getDeclaredFields(); if(fields.length!=0){ for(Field beanField:fields){ //判断是否需要注入 if(beanField.isAnnotationPresent(Inject.class)){ Class<?> beanFieldClass=beanField.getType(); Object beanFieldInstance=beanMap.get(beanFieldClass); if(beanFieldInstance!=null){ ReflectionUtil.setField(beanInstance,beanField,beanFieldInstance); } } } } } } }}
测试:
定义一个Service
@Servicepublic class LoginService { public LoginService(){} public void login(){ System.out.println("login..."); }}
再定义一个Controller,依赖于Service
@Controllerpublic class IndexController { @Inject private LoginService loginService; public void login(){ System.out.println("call login method"); loginService.login(); }}
测试IOCHelper,是否注入了Service(@service,@Controller标记的类会被装配成Bean)
public class Start { public static void main(String[] arg){ ClassUtil.loadClass(IOCHelper.class.getName(), true); IndexController controller= BeanHelper.getBean(IndexController.class); controller.login(); }}
总结
到这里相信你已经了解了IOC容器的大概工作方式(,这里的IOCHelper还存在一些不足:
1. 只支持Bean的属性注入,没有支持方法或者构造函数。
2. BeanMap中所有的Class都是单例的,每次getBean得到的都是同一实例。
完整代码地址
- 动手编写一个IOC容器
- 容器学习(一):动手模拟spring的IoC
- 跟我动手搭框架一之IOC容器实现
- 动手编写一个以太坊智能合约
- 自己动手编写IoC容器(一)
- 动手实现IOC
- 深入理解Spring--动手实现一个简单的SpringIOC容器
- 对Ioc容器的一个期望
- 关于DIP,IoC,DI,以及IoC容器的一个说明
- IoC容器
- IOC容器
- IoC 容器
- Ioc容器
- Ioc容器
- IoC容器
- IOC + 容器
- IoC容器
- IoC容器
- iOS简单直播实现(一:创建本地rtmp服务器)Mac上搭建直播服务器Nginx+rtmp
- python自学笔记12之anaconda
- java如何从数据库读出内容放到jsp中
- Tomcat的跨区域访问问题
- Android中activity的生命周期相关~
- 动手编写一个IOC容器
- 集合入门介绍第三章——Set集合
- opencv实现类似MATLAB中find功能的方法
- hdu2255——奔小康赚大钱(二分图最优匹配+KM算法)
- Android中SP与DP区别的自我理解
- PHP生成唯一字符串的方法,产生唯一码的方法分析
- DescriptionResourcePathLocationType Cannot change version of project facet Dynamic Web Module to
- CodeForces 132C Logo Turtle 四维DP 递推
- Voucher Key 相关SELinux