想要全面的了解spring 那么我们首先要了解是什么是依赖注入(DI)和控制反转(Ioc)。
public class Worker {
private Person person;
public Worker(Person person) {
this.person = person;
}
}
如上段代码,Worker依赖Person,Person通过Worker的构造函数注入到Worker类。这就是依赖注入。注入的方式还有setter注入和接口注入。
控制反转
public class Worker {
private Person person;
public Worker() {
this.person = new Person();
}
}
上段代码,worker 依赖 Person,底层依赖上层 ,传统应用的话使用worker需要自己newPerson对象。这两个类之间高耦合。有了依赖注入之后(把底层类作为参数传入上层类,实现上层类对对下层类的控制),用构造方法实现的依赖注入实现控制反转。
因为采用了依赖注入,在初始化的过程中就不可避免的会写大量的new。这里IoC容器就解决了这个问题。这个容器可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码),而不用每次初始化一辆车都要亲手去写那一大段初始化的代码。这是引入IoC Container的第一个好处。
IoC Container的第二个好处是:我们在创建实例的时候不需要了解其中的细节。在上面的例子中,我们自己手动创建一个车instance时候,是从底层往上层new的:
创建 一个Worker实例——》new Person()——》注入new Worker()
这个过程中,我们需要了解整个Worker/Person类构造函数是怎么定义的,才能一步一步new/注入。
而IoC Container在进行这个工作的时候是反过来的,它先从最上层开始往下找依赖关系,到达最底层之后再往上一步一步new(有点像深度优先遍历):
创建一个Worker实例——》查config——》需要Person——》往上创建——》new Person——》注入——》new Worker()
这里IoC Container可以直接隐藏具体的创建实例的细节,在我们来看它就像一个工厂:
创建一个Worker实例——》查config——》需要Person——》往上创建——》new Person——》注入——》new Worker()
我们就像是工厂的客户。我们只需要向工厂请求一个Worker实例,然后它就给我们按照Config创建了一个Worker实例。我们完全不用管这个Worker实例是怎么一步一步被创建出来。
Spring中的依赖注入
上面我们提到,依赖注入是实现控制反转的一种方式。下面我们结合Spring的IoC容器,简单描述一下这个过程。
class MovieLister...
private MovieFinder finder;
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
class ColonMovieFinder...
public void setFilename(String filename) {
this.filename = filename;
}
我们先定义两个类,可以看到都使用了依赖注入的方式,通过外部传入依赖,而不是自己创建依赖。那么问题来了,谁把依赖传给他们,也就是说谁负责创建finder,并且把finder传给MovieLister。答案是Spring的IoC容器。要使用IoC容器,首先要进行配置。这里我们使用xml的配置,也可以通过代码注解方式配置。下面是spring.xml的内容
"MovieLister" class="spring.MovieLister">
"finder">
"MovieFinder"/>
"MovieFinder" class="spring.ColonMovieFinder">
"filename">
movies1.txt
在Spring中,每个bean代表一个对象的实例,默认是单例模式,即在程序的生命周期内,所有的对象都只有一个实例,进行重复使用。通过配置bean,IoC容器在启动的时候会根据配置生成bean实例。具体的配置语法参考Spring文档。这里只要知道IoC容器会根据配置创建MovieFinder,在运行的时候把MovieFinder赋值给MovieLister的finder属性,完成依赖注入的过程。下面给出测试代码
public void testWithSpring() throws Exception {
ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");//1
MovieLister lister = (MovieLister) ctx.getBean("MovieLister");//2
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}
总结
控制反转是一种在软件工程中解耦合的思想,调用类只依赖接口,而不依赖具体的实现类,减少了耦合。控制权交给了容器,在运行的时候才由容器决定将具体的实现动态的“注入”到调用类的对象中。
依赖注入是一种设计模式,可以作为控制反转的一种实现方式。依赖注入就是将实例变量传入到一个对象中去(Dependency injection means giving an object its instance variables)。
通过IoC框架,类A依赖类B的强耦合关系可以在运行时通过容器建立,也就是说把创建B实例的工作移交给容器,类A只管使用就可以。
参考链接:https://blog.csdn.net/Mus_Li/article/details/77921205