Spring IoC容器之基本概念

304 阅读3分钟

这是我参与更文挑战的第2天,活动详情查看:更文挑战

IoC全称Inversion of Control,控制反转,也叫做依赖注入(Dependency Injection)。那么,为什么需要IoC?IoC的具体意义是什么?让我们来引入一个简单场景来解释。

在一个外汇交易(FX)项目中,需要实时地为客户提供外汇新闻,通常情况下,需要先从不同的新闻社订阅新闻来源,然后通过批处理程序定时地到指定新闻服务器抓取最新的外汇新闻,接着将这些新闻存入本地数据库中,最后在前端显示。

假设由FXNewsProvider来完成以上工作

public class FXNewsProvider {
    private IFXNewsListener newsListener;
    private IFXNewsPersister newsPersister;
    public void getAndPersistNews(){
       String[] newsIds = newsListener.getAvailableNewsIds();
       if (newsIds.length == 0) return ;
       for (String newsId : newsIds){
           FXNewsBean newsBean = newsListener.getNwesByPK(newsId);
           newsPersister.persistNews(newsBean);
           newsListener.postProcessIfNecessary(newsId);
       }
    }
}

FXNewsProvider依赖 newsListener来抓取新闻,newsPersister存储新闻,所以需要在构造函数中构造这两个依赖类

public FXNewsProvider(){
        newsListener = new DJNewsListener();
        newsPersister = new DJNewPersister();
}

在没有IoC之前,我们通常是以上这种做法。每次用到什么依赖对象都要主动地去获取,这真的必要嘛?我们最终要做的只是调用依赖对象提供的服务而已。所以IoC就是帮我们做了这些和业务逻辑无关的事情。

在IoC模式中,被注入的对象又是通过哪些方式来通知上图中的女生(IoC Service Provider)来为其提供适当的服务的呢?在权威文章中总结了有三种依赖注入的方式:1.构造方法注入 2.setter方法注入 3.接口注入

1.构造方法注入

public FXNewsProvider(IFXNewsListener newsListener, IFXNewsPersister newsPersister){
        this.newsListener = newsListener;
        this.newsPersister = newsPersister;
    }

2.setter方法注入

public class FXNewsProvider {
    private IFXNewsListener newsListener;
    private IFXNewsPersister newsPersister;
    
    public IFXNewsListener getNewsListener() {
        return newsListener;
    }
​
    public void setNewsListener(IFXNewsListener newsListener) {
        this.newsListener = newsListener;
    }
​
    public IFXNewsPersister getNewsPersister() {
        return newsPersister;
    }
​
    public void setNewsPersister(IFXNewsPersister newsPersister) {
        this.newsPersister = newsPersister;
    }
}

3.接口注入 在这种情况下,实现的接口和接口中声明的方法名都不重要,重要的是接口中声明方法的参数类型,必须是”被注入对象“所依赖对象的类型。

三种方式的比较 接口注入:从注入方式的使用上来说,接口注入是现在不提倡的一种方式,基本处于”退役“状态。因为它强制被注入对象实现不必要的接口,带有侵入性。

构造方法注入:优点是,对象在构造完成之后,即已经进入就绪状态,可以马上使用。缺点是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反射构造对象时,对相同类型的参数处理会比较困难,维护也比较麻烦。

setter方法注入:因为方法可以命名,所以setter方法注入在描述性上要比构造方法注入好。另外setter方法可以被继承,允许设置默认值,有良好的IDE支持。缺点就是无法在构造完成后马上进入就绪状态。