通过简单实现来理解控制反转(IOC)和依赖注入(DI)
IOC (控制反转Inversion of control)和依赖注入(DI)是Spring的一个重要特性,这里试图通过一个简单的例子来理解这个特性。
IOC是指控制权的转移。举例来说,在一个一般的类中,如果我们需要用到一些其他对象(不是由构造方法传递,或者从父类继承),正常情况下要使用它们,首先应该获取它,否则就无法使用。
这在一段不长的代码中自然没有什么问题,人脑可以轻松处理这些问题.然而随着开发进行创建的东西越来越多,各个部分的依赖会变得越来越复杂,处理这些就会非常的困难.
我们自然不想处理这些复杂的关系,这会让人的脑袋爆炸的.而这种问题由计算机来处理是很轻松的.IOC就是处理这种问题的方法.
我们想要达到的目的是:我们不需要考虑对象是怎么创建的,只要需要用到对象的时候从容器中获取一个就行。
Spring就是这样一个容器,在创建一个ApplicationContext时,我们从一个外部xml配置文件中读取配置文件,创建其指定的对象,并把它放到容器中去。需要使用对象的时候直接从容器中获取,不需要重复创建。
下面我们来实现一个类似Spring的简单容器,读取类路径下的配置文件,创建容器,在使用对象的时候直接从容器中获取。
首先新建两个我们想要获取的简单的类
public class MyOrder { private OrderDao orderDao; public void print(){ System.out.println("print"); orderDao.select; } }
public class OrderDao { public void select(){ System.out.println("select"); } }
新建一个properties配置文件,在里面配置这两个类的bean名称和类全名。
myOrder=cn.acgq.MyOrder orderDao=cn.acgq.OrderDao
接下来就是创建容器了,创建了一个名为BeanFactory的容器,代码如下:
public class BeanFactory { //使用Map来存放beanName和Instance映射 private static Map<String, Object> beans = new HashMap<>(); //创建bean名字和类的映射 static { //加载配置文件 try { properties.load(BeanFactory.class.getResourceAsStream("/config.properties")); } catch (IOException e) { throw new RuntimeException(e); } properties.load(this.class.getResourceAsStream("/config.properties")); properties.forEach((bean, beanClass) -> { try { //根据配置文件创建bean,将其放到Map中去 Class clazz = Class.forName((String) beanClass); Object beanInstance = clazz.getConstructor().newInstance(); beans.put((String) bean,beanInstance); } catch (Exception e) { throw new RuntimeException(e); } }); //依赖注入 // beans.forEach((beanName,beanInstance) -> // dependencyInjection(beanName,beanInstance,beans)); } public static Object getBean(String beanName){ return beans.get(beanName); } }
通过java的反射,我们实现了根据类名创建实例,这样我们就能从beanFactory中根据名称获取bean了。
MyOrder myOrder= (MyOrder) BeanFactory.getBean("myOrder");
当然到这里还没有结束,这里新创建的实例里成员变量为空,如果执行print方法会报错。我们还需要把beanFactory中生成的OrderDao注入MyOrder。
这里我们使用注解的方式进行,新建一个注释,表示这个成员变量需要自动注入。
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Resources { }
在MyOrder中的OrderDao上添加注释
@Resources private OrderDao orderDao;
新建方法 dependencyInjection进行注入
private static void dependencyInjection(String beanName, Object beanInstance,Map<String,Object> beans) { //过滤出需要注入的字段 List<Field> fieldToBeAutowired = Stream.of(beanInstance.getClass().getDeclaredFields()) .filter(field -> field.isAnnotationPresent(Resources.class)) .collect(Collectors.toList()); //进行注入 fieldToBeAutowired.forEach(field -> { String fieldName=field.getName(); field.setAccessible(true);//private字段需要进行这一操作 Object dependencyBeanInstance = beans.get(fieldName); try { //设置field field.set(beanInstance,dependencyBeanInstance); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }); }
到这里就完成了一个简单的IOC容器,来测试一下吧
public class TestIOC { public static void main(String[] args) { MyOrder myOrder= (MyOrder) BeanFactory.getBean("myOrder");myOrder.select(); } }
输出结果如下
MyOrder select orderDao
当然了,Spring肯定不是这么简单的实现,它在实现IOC的时候做了大量的事,代码里有非常多的细节处理。这里只是用一个简单的例子理解IOC和DI的实现
- 点赞
- 收藏
- 分享
- 文章举报
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
- Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)
- 个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解
- ASP.NET MVC进阶之路:深入理解依赖注入(DI)和控制反转(IOC)
- 如何理解Spring的控制反转IOC和依赖注入DI思想
- iOS控制反转(IoC)与依赖注入(DI)的实现
- 利用反射简单模拟Spring的控制反转(Ioc)和依赖注入(DI)
- 深入理解控制反转(IoC)和依赖注入(DI)
- iOS控制反转(IoC)与依赖注入(DI)的实现
- 如何理解Spring的控制反转IOC和依赖注入DI思想
- 轻松理解 Java开发中的依赖注入(DI)和控制反转(IOC)
- Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)
- laravel服务容器-----深入理解控制反转(IoC)和依赖注入(DI)
- 代码的演化-DI(理解依赖注入di,控制反转ioc)
- 有史以来最容易理解的控制反转(IoC)与注入依赖(DI)
- 代码的演化-DI(理解依赖注入di,控制反转ioc)
- Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)
- 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。
- Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)
- laravel服务容器-----深入理解控制反转(IoC)和依赖注入(DI)