IoC 控制反转

第一次听到这个名词的时候,我就在想到底是哪个“天才”想出来这么丑陋的名字的?当时看了一些博客知道是解决依赖关系的,但是“控制”和“反转”一直没有解释是什么意思。

初始化对象

为了解释这个名词,先来看我们初学时候是怎么初始化对象的。

当我们执行 Java 程序时最关键的步骤是要 new 对象的,比如 String s = new String(),再比如自己写了一个 Stack,测试也好,去做真的 Stack 操作第一步也要 Stack stack = new Stack()。因此,刚开始学 Java 的时候,我们一般都会在 public void main() 这个方法里去初始化我们自己写的类。

比如这是我练习多态时写的。

public void main(String[] args) {
  Animal animal = new Animal();
  Animal cat = new Cat();
  Animal dog = new Dog();
  ...
}

上面的初始化很简单,如果我们要在类里面初始化,可能会在构造器或者字段里 new 对象:

private List<Cat> children = new ArrayList()<>;
private Body body;

public Cat(Leg leg, Arm arm) {
  this.body = new Body(leg, arm);
}

总结一下我们上面初始化对象的步骤:找一个入口,即 main 方法,开始执行,用到哪个类就 new 哪个类,如果里面有成员也要 new,就在所在的类里去先 new 了,再用。

问题

上面这种初始化对象的方法很直观,但是不能应对庞大的项目,而且当类之间互相依赖变多的时候,我们就要在他们的 constructor 里不断地手写:XXX x = new XXX();;而且有些类是不能直接 new 的,可能是单例类,要用工厂方法获取对象,这个时候可能会把你烦死。

解决方案

这让我们不禁想到:其实这些 new XXX() 或者 new XXX(a, b, c) 又或者 XXX x = XXXFactory.make() 都是一些固定的代码。就跟 setter,getter 一样。当看到 xxx 变量时,脑海自动会有 getXXXsetXXX,那这些 new 对象的代码为什么不可以自动化呢?

为了让 Java 能识别那些需要被 new 出来的对象,一个简单的想法就是我加个标记呗:

private DataService Singleton service;

这里的 Singleton 代表 service 要被 new 成一个单例。但是这里语法不行啊,限定符只能是 private, static 啥的。这个时候注解就是我们最佳的选择了。

@Singleton
private DataService serivce;

我们还可以定义别的注解如:@Autowiared,@Inject,@Factory,....(当然有些是我编的),然后写个 Java 程序先去检测到带注解的变量,把这些需要自动装配的变量拿出来,然后每个变量都自动 new 自己,这不就是完美的自动化了么?

除此之外,我们还发现有些类的自动装配不仅仅是 XXX x = new XXX 这么简单,比如新建一个数据库连接池,最好是

  1. 自动读取配置文件(用户名,密码,数据库 url 等)
  2. 新建对象
  3. 初始化池里的一些东西
  4. ...

因此我们还要将这些要被自动装配的类去细分成 @Service、@Bean、@Application...... 等

控制反转

先总结一下上面的解决方案:我们用注解去标识一些类,如 @Service 等。使用当用这些类作为成员变量时,我们再在上面加个注解,如 @Autowired 等,用来表示要自动装配(或者花样自动装配)。然后写个 Java 程序,将需要自动装配的变量都弄成一个 List,遍历 List,动态去 new 对象。至于怎么个 new 法要看注解是啥。

从上面看到这个 Java 自动装配程序比较关键啊,所以这里提供一个装配单例对象的简化代码:

  1. 先 new 好对象,类的关系都放在 ioc.properties 里
Properties properties = new Properties();
properties.load(XXX.class.getResourceAsStream("./ioc.properties");

// 每个 Bean 都 new 一下,这里用 getConstructor().newInstance() 完成的
properties.forEach((beanName, beanClass) -> {
  Class<?> klass = Class.forName((String) beanClass);

  Object beanInstance = klass.getConstructor().newInstance();

    beans.put((String) beanName, beanInstance);
})
  1. 把有注解的变量弄出来,自动装配
beans.forEach((beanName, beanInstance) -> 
    // 将带有 @Autowired 注解的变量成员弄出来
    Listfb<Field> fields = Stream.of(beanInstance.getClass().getDeclaredFields())
                            .filter(field -> field.getAnnotation(Autowired.class) != null)
                            .collect(Collectors.toList());

    // 装配之前 new 好的对象
    fields.forEach(field -> {
        String fieldName = field.getName();
        Object obj = beans.get(fieldName);
        
        field.setAccessible(true);
        field.set(beanbeanInstance, obj);
    })
})

这就是所谓的控制反转,意思就是本来是需要你自己手动去 new Java对象的,现在变成 Java 去帮你 new Java对象了,相当于把控制权交给 Java 。

所以嘛,反转的意思就是本来你控制 Java 程序,现在 Java 程序控制了你?Emm 听起来怪怪的,但是说 Java(自动装配) 控制了 Java(你的应用)好像也不算反转吧?所以我说这个名字是真的丑陋。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249