依赖注入 DI
什么是依赖
依赖的解释:依赖是一种关系,一个类依赖另一个类,也就是一个类中有另一个类的引用,class Person 中有 class Car 的引用那就叫 Person 对 Car 有一个依赖。
// Person对Car有一个依赖 class Person { Car car; public Person() { car = new Car(); } }
什么是依赖注入
我们一开始学 Java 对于上面的构造方法里面我们如何给 car 引用对象呢?我们的第一反应是啥,new 一个对象,这也就是我们的习惯思维,调用者来创建被调用者的实例,而在依赖注入的思想里,我们不是直接 new 对象了,而是通过传递外部引用,也就是通过外部注入依赖。
//外部注入依赖 class Person { Car car; public Person(Car car) { this.car = car; } }
这里面调用者不在控制car的实例的实现了所以叫控制反转(IoC, Inversion of Control)实际上和依赖注入(DI, Dependency Injection)是一个意思。
依赖注入的意义
我来好好解释为啥要依赖注入,比如上面的 Person 类,如果我的 Person 类中的 car 从本来的奇瑞qq变大奔,我是不是要再改 Person 类中的构造方法,是不是很麻烦,这里面 person 和 car 紧密的耦合在一起,我们也就写死了 car 在 Person 类中而且 new 对象过程也很慢。而通过外部注入依赖的方式我不需要再改 Person 类中的代码,我写我的大奔代码传入大奔就行了,这也就说明了为啥要依赖注入,因为可以解耦。
依赖注入主要作用:依赖注入能够让相互协作的软件组件保持松散耦合
Spring 依赖注入
依赖注入(DI, Dependency Injection),也叫控制反转(IoC, Inversion of Control)是 Spring 框架的核心机制,相当于心脏对于人的重要性,只有真正理解这些核心的功能,才有能力使用 Spring 框架。
Spring 中的依赖注入就是上面说的外部,实例不在由程序员实例化,而是通过 Spring 容器帮我们 new 指定实例并且将实例注入到需要该对象的类。我们不用关心 Car 的变化,实例之间的依赖关系由 IOC 容器负责了,等待 Spring 依赖注入。
IOC 和 DI
IOC(inversion of control):其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发送请求查找资源。作为回应,容器适时的返回资源。而应用ll额IOC之后,则是容器主动的向资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。这种行为也称为查找的被动形式。
DI(Dependency Injection)—— IOC的另一种表达方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自如容器的资源注入,相对 IOC 而言,这种表述更直接。
控制反转 IOC
什么是 IOC
控制反转(Inversion of Control,缩写为 IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。
为什么使用 IOC
在日常程序开发过程当中,我们推荐面向抽象编程,面向抽象编程会产生类的依赖,当然如果你够强大可以自己写一个管理的容器,但是既然 Spring 以及实现了,并且 Spring 如此优秀,我们仅仅需要学习 Spring 框架便可。
当我们有了一个管理对象的容器之后,类的产生过程也交给了容器,至于我们自己的 app 则可以不需要去关系这些对象的产生了。
Spring 实现 IOC 的思路和方法
Spring 实现 IOC 的思路是提供一些配置信息用来描述类之间的依赖关系,然后由容器去解析这些配置信息,继而维护好对象之间的依赖关系,前提是对象之间的依赖关系必须在类中定义好,比如 A.class 中有一个 B.class 的属性,那么我们可以理解为 A 依赖了 B。既然我们在类中已经定义了他们之间的依赖关系那么为什么还需要在配置文件中去描述和定义呢?
Spring 实现 IOC 的思路大致可以拆分成3点:
应用程序中提供类,提供依赖关系(属性或者构造方法)。
把需要交给容器管理的对象通过配置信息告诉容器(xml、Annotation,JavaConfig)。
把各个类之间的依赖关系通过配置信息告诉容器。
配置这些信息的方法有三种分别是xml,Annotation 和 JavaConfig 维护的过程称为自动注入,自动注入的方法有两种构造方法和 setter 自动注入的值可以是对象,数组,map,list 和常量,比如字符串、整型等。
Spring 编程的风格
schemal-based xml annotation-based annotation java-based java Configuration - 注入的两种方法
Constructor-based Dependency Injection
构造方法注入参考文档:
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-constructor-injection
Setter-based Dependency Injection
setter 参考文档:
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection
注意:如果生成的是 String 类型,那么在 xml 配置的 property 中的属性将从 ref 替换成 value。
这两种方式我们只要知道就好了,因为配置起来很麻烦,还有另外一种方式,使用注解注入。
注解注入
- Spring 使用注解,通过 "@XXX" 的方式,让注解与 Java Bean 紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。
常用的注解有四个:
@Controller 用于标注控制层组件,即 Web 业务层。 @Service 用于标注业务层组件,即 Service 层。 @Repository(value="indexDao") 用于标注数据访问组件,即 Dao 层。 @Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。 定义在类中的属性的注解:
@Value(value="112") 给简单类型属性赋值,可以用在方法上或属性上。 @Resource(name="user") 给对象引用类型赋值,该值 user 类必须已经声明(在配置文件中已配置或在类中已经注解)。 - 当我们注入之后就需要使用,我们在一个类中使用另一个类,不需要去 new 一个对象,而是使用注解的方式实现装配。
@Autowired 特点:
@Autowired 是 按照类型 自动注入,适用于容器中只有一种该类型的组件。
如果存在多个相同类型的组件,则将属性名作为
id
查询容器中的组件并注入。默认属性对应的组件在容器中必须是存在的,如果想无论存在与否都注入可以令属性
required = false
使其不抛出异常,属性默认为 null。可以在该注解的基础之上使用
@Qualifier("bookDao")
注解指定要注入组件的id
,这时属性名的id
已失效。如果不使用上述注解指定
id
,存在多个相同类型的组件时也可以使用@Primary
注解设置Bean
的优先级为最优。@Resource:
与
@Autowired
不同,@Resource
注解是 按照属性名 自动注入,它属于JSR250
规范。该注解不支持
@Qualifier
、@Primary
的使用,但是可以使用它的name
属性指定要注入组件的id
值。@Inject:
要使用
@Inject
注解必须要先导包,它属于JSR330
规范 :<!-- inject 注解 --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
导包之后就可以使用了,该注解的效果和
@Autowired
的效果一样,只不过没有任何属性,所以功能有些欠缺,但是可以和另外两个注解配合使用。
有兴趣的同学可以关注我的个人公众号,期待我们共同进步!!!