IOC
在有 IOC 概念之前,我们要使用一个对象,通常会使用 Object obj = new Object()
,这种实现方式存在以下问题:
- 高耦合。如果一个地方用到还好,假设项目中很多地方都要用到该对象,就会在每个地方去 new ,这样子呢就会和业务代码等紧耦合。
- 扩展性不好。如果以后实现方式有变化,那么可能就需要批量替换的方案,但是也会引来一定的风险,并且有些可能根本无法替换。
那么是否可以使用工厂模式取代 new
操作呢?这样子如果变更的话,只需要改变工厂方法的实现即可。其实这样只是将 new
对象的问题延迟到了工厂方法里而已。
那么我们是否可以不关心要使用的对象是如何创建的,当要用的时候就可以直接用呢?Spring IOC 就能做到。先不用去看 IOC 实现源码,我们大概来猜测一下,Spring IOC 做了哪些工作呢?
- 首先摆在我们面前的是,由于现在不直接 new 了,那要去哪里找对象呢?通常情况下,对象会存放在外部,比如 xml 文件里。所以第一个是需要将资源定位。
- 定位之后,就需要将外部对象加载到 Spring 的数据结构中,这个数据结构在 Spring 中叫做 BeanDefinition。
- 当然,最后我们还需要将 BeanDefinition 注册到 IOC 容器中,也就是将加载到的 BeanDefinition 放入到
Map<String,BeanDefinition>
,其中 key 是 beanName,value 是 BeanDefinition。
DI
DI 中文翻译为依赖注入,其中核心为 反射。下面我们使用自定义注解来模拟 Spring 的 Autowired。
-
先定义自定义注解类
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }
-
定义 Controller
public class TestController { @Autowired private TestService testService; public void print() { System.out.println(testService); } }
-
编写一个测试类
public class TestControllerTest { @Test public void test() { TestController testController = new TestController(); Field[] declaredFields = testController.getClass().getDeclaredFields(); Arrays.stream(declaredFields).forEach(field -> { Autowired annotation = field.getAnnotation(Autowired.class); if (annotation != null) { try { field.setAccessible(true); Class<?> type = field.getType(); // 该例子中使用的 type.getConstructor().newInstance(); // Spring 中使用的是 IOC 容器获取 Object o = type.getConstructor().newInstance(); field.set(testController, o); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } } testController.print(); }); } }
如上,便可以实现我们自定义的依赖注入,可以看到核心原理就是利用了 Java 的反射机制,只不过在本例中,我们通过 type.getConstructor().newInstance();
创建类的实例,而在 Spring 中使用 IOC 容器管理。
网友评论