Spring|IOC与DI
一、IOC
IOC(Inversion of Control),控制反转,是Spring的核心内容之一。
什么是“控制反转”?
【示例】
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:29
- */
- public class Person {
- private String id;
- private String name;
- private Address address;
- public Person() {
- this.id = "1001";
- this.name = "张三";
- this.address = new Address();
- }
- }
如上定义了类Person,并在构造函数中对其属性进行赋值。这种方式虽然简单,但是代码的重用性不强,而且耦合度很高,所以我们可以做如下更改:
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:29
- */
- public class Person {
- private String id;
- private String name;
- private Address address;
- public Person(String id, String name, Address address) {
- this.id = id;
- this.name = name;
- this.address = address;
- }
- }
这种方式,将类中属性赋值的权利,交由第三方。提高了代码的重用性,并降低了耦合度。基于这个思想,Spring为我们提供了另一种更加灵活的方式,代码如下:
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:29
- */
- public class Person {
- private String id;
- private String name;
- private Address address;
- public Person(String id, String name, Address address) {
- this.id = id;
- this.name = name;
- this.address = address;
- }
- public Person() {
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Address getAddress() {
- return address;
- }
- public void setAddress(Address address) {
- this.address = address;
- }
- }
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:30
- */
- public class Address {
- private String country;
- private String province;
- private String city;
- public String getCountry() {
- return country;
- }
- public void setCountry(String country) {
- this.country = country;
- }
- public String getProvince() {
- return province;
- }
- public void setProvince(String province) {
- this.province = province;
- }
- public String getCity() {
- return city;
- }
- public void setCity(String city) {
- this.city = city;
- }
- }
xml配置
- <bean id="person" class="com.my.Person">
- <constructor-arg type="java.lang.String" value="1001"/>
- <constructor-arg type="java.lang.String" value="张三"/>
- <constructor-arg type="com.my.Address" ref="address"/>
- </bean>
- <bean id="address" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- package com.my;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/13 10:06
- */
- public class MainApp {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
- Person person = (Person) context.getBean("person");
- System.out.println(person.getName());
- Address address = person.getAddress();
- System.out.println(address.getCountry() + "-" + address.getProvince() + "-" + address.getCity());
- }
- }
执行结果:
- 张三
- 中国-江苏省-南京市
Spring提供的这种方式将传统上由程序代码直接操控的对象的调用权交给外部容器,通过容器来实现对象组件的装配和管理。
所谓的“控制反转”概念就是组件对象的控制权转移了,从程序代码本身转移到了外部容器。
IOC最常见的一种应用场景,就是配置数据库连接。我们将操作数据库的对象交由容器进行统一管理。
二、IOC容器
Spring容器是Spring框架的核心,容器创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些被创建的对象被称为Spring Beans。
通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML或 Java 代码(参考3.4)来表示。
Spring IOC容器利用Java的POJO类和配置元数据来生成Spring Beans。
2.1、IOC容器-BeanFactory
这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactory 中被定义。 BeanFactory 和相关的接口,比如BeanFactoryAware、 DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。
在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。
在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。
【示例】
- XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("Beans.xml"));
- Person person = (Person) factory.getBean("person");
- System.out.println(person.getName());
2.2、IOC容器-ApplicationContext
Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface接口中定义。
ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。
最常被使用的 ApplicationContext 接口实现:
FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
- //负责生成和初始化所有的对象,即所有在 XML bean 配置文件中的 bean。
- ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
- //利用 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。
- Person person = (Person) context.getBean("person");
- System.out.println(person.getName());
- Address address = person.getAddress();
- System.out.println(address.getCountry() + "-" + address.getProvince() + "-" + address.getCity());
三、DI
DI(Dependency Injection),依赖注入,控制反转(IOC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
3.1、什么是依赖注入?
让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。这意味着类 B 将通过 IOC 被注入到类 A 中。
依赖注入可以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。
【举例】
在第一个示例中,我们已经使用构造函数进行依赖注入,下面我们说第二种方法:
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:29
- */
- public class Person {
- private String id;
- private String name;
- private Address address;
- public Person() {
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Address getAddress() {
- return address;
- }
- public void setAddress(Address address) {
- this.address = address;
- }
- }
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:30
- */
- public class Address {
- private String country;
- private String province;
- private String city;
- public String getCountry() {
- return country;
- }
- public void setCountry(String country) {
- this.country = country;
- }
- public String getProvince() {
- return province;
- }
- public void setProvince(String province) {
- this.province = province;
- }
- public String getCity() {
- return city;
- }
- public void setCity(String city) {
- this.city = city;
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
- <bean id="person" class="com.my.Person">
- <property name="id" value="1001"/>
- <property name="name" value="张三"/>
- <property name="address" ref="address"/>
- </bean>
- <bean id="address" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- </beans>
- package com.my;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/13 10:06
- */
- public class MainApp {
- public static void main(String[] args) {
- //负责生成和初始化所有的对象,即所有在 XML bean 配置文件中的 bean。
- ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
- //利用 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。
- Person person = (Person) context.getBean("person");
- System.out.println(person.getName());
- Address address = person.getAddress();
- System.out.println(address.getCountry() + "-" + address.getProvince() + "-" + address.getCity());
- }
- }
输出结果:
- 张三
- 中国-江苏省-南京市
两种方式的返回结果一致
3.2、自动装配-依赖注入
Spring 容器可以在不使用<constructor-arg>和<property>元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。
其中较常用的两种方式,“byName”和“byType”
【举例】
“byName”,配置文件中的属性autowire=“byName”,并且Person类中包含属性address,及其setAddress(..)方法,那么spring就会查找配置文件中id=“address”的bean进行自动装配。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
- <bean id="person" class="com.my.Person" autowire="byName">
- <property name="id" value="1001"/>
- <property name="name" value="张三"/>
- </bean>
- <bean id="address" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- </beans>
“byType”,配置文件中的属性autowire=“byType”,并且Person类中包含属性address,及其setAddress(..)方法。address由Address类声明,那么spring就会查找配置文件中类型为Address类的bean进行自动装配。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
- <bean id="person" class="com.my.Person" autowire="byType">
- <property name="id" value="1001"/>
- <property name="name" value="张三"/>
- </bean>
- <bean id="address" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- </beans>
3.3、注解装配-依赖注入
从 Spring 2.5 开始就可以使用注解来配置依赖注入。注解默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解之前,我们将需要在我们的 Spring 配置文件中启用它。
- <!--开启注解-->
- <context:annotation-config/>
@Required:作用于属性的setter方法,标明属性必须在配置文件中声明,否则会抛出异常。
- @Required
- public void setAddress(Address address) {
- this.address = address;
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <!--开启注解-->
- <context:annotation-config/>
- <bean id="person" class="com.my.Person">
- <property name="id" value="1001"/>
- <property name="name" value="张三"/>
- <!--<property name="address" ref="address"/>-->
- </bean>
- <bean id="address" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- </beans>
输出结果:抛出“BeanInitializationException”异常
@Autowired:可以作用于类的构造方法,属性的setter方法及属性本身。利用“byType”模式,实现属性值的自动装配。
- package com.my;
- import org.springframework.beans.factory.annotation.Autowired;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:29
- */
- public class Person {
- private String id;
- private String name;
- private Address address;
- public Person() {
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Address getAddress() {
- return address;
- }
- @Autowired
- public void setAddress(Address address) {
- this.address = address;
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <!--开启注解-->
- <context:annotation-config/>
- <bean id="person" class="com.my.Person">
- </bean>
- <bean id="address" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- </beans>
执行结果:
- null
- null
- 中国-江苏省-南京市
虽然配置文件中,没有配置address属性与com.my.Address之间的关联关系,但是通过注解@Autowired,实现属性的自动装配。
我们也可以在属性本身及类构造函数上声明@Autowired,例如:
- @Autowired
- private Address address;
- @Autowired
- public Person(Address address) {
- this.address = address;
- }
@Qualifier:当创建多个类型相同的bean时,@Autowired就不能唯一确定该调用哪个bean进行自动装配,这个时候就需要@Qualifier来消除混乱。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <!--开启注解-->
- <context:annotation-config/>
- <bean id="person" class="com.my.Person">
- </bean>
- <bean id="address1" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="南京市"/>
- </bean>
- <bean id="address2" class="com.my.Address">
- <property name="country" value="中国"/>
- <property name="province" value="江苏省"/>
- <property name="city" value="苏州市"/>
- </bean>
- </beans>
- @Autowired
- @Qualifier("address2")
- private Address address;
执行结果:
- 中国-江苏省-苏州市
@Resource:区别于上面的注解,此注解是jdk提供的,不是spring的特性。可以作用于属性及其setter方法,利用“byName”模式,实现属性值的自动装配。
- @Resource(name="address1")
- private Address address;
执行结果:
- 中国-江苏省-南京市
也可以直接使用 @Resource,而不声明name,这时就通过属性名进行查找。
3.4、基于java的配置元数据
以上的配置均是基于XML配置元数据,下面我们将演示如何通过代码及注解完成元数据配置。
- package com.my;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/16 11:29
- */
- public class Person {
- private String id;
- private String name;
- private Address address;
- public Person() {
- }
- public Person(Address address) {
- this.address = address;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Address getAddress() {
- return address;
- }
- public void setAddress(Address address) {
- this.address = address;
- }
- }
- package com.my;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/8/2 17:49
- */
- @Configuration
- public class AnnotationConfig {
- @Bean
- public Person person() {
- return new Person(address());
- }
- @Bean
- public Address address() {
- return new Address("中国", "江苏", "无锡");
- }
- }
- package com.my;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.annotation.AnnotationConfigApplicationContext;
- /**
- * @Author jyy
- * @Description {}
- * @Date 2018/7/13 10:06
- */
- public class MainApp {
- public static void main(String[] args) {
- ApplicationContext ctx = new AnnotationConfigApplicationContext(AnnotationConfig.class);
- Person person = ctx.getBean(Person.class);
- Address address = person.getAddress();
- System.out.println(address.getCountry() + "-" + address.getProvince() + "-" + address.getCity());
- }
- }
输出结果:
- 中国-江苏-无锡
带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。
在这里,带有 @Bean 注解的方法名称作为 bean 的 ID,它创建并返回实际的 bean,比如address()中的“address”为bean的ID。
Spring|IOC与DI的更多相关文章
- Spring IoC 和 DI 简介(二)
Spring IoC 和 DI 简介 IoC:Inverse of Control(控制反转) 读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由 ...
- Spring 学习教程(一):浅谈对Spring IOC以及DI的理解
一.个人对IoC(控制反转)和DI(依赖注入)的理解我们平时在开发java web程序的时候,每个对象在需要使用它的合作对象时,自己都要将它要合作对象创建出来(比如 new 对象),这个合作对象是由自 ...
- Spring IOC(DI)
软件152 余建强 1 什么是IOC IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不 ...
- (转)spring IOC、DI理解
转自: http://www.cnblogs.com/xdp-gacl/p/4249939.html 个人理解: IOC控制反转,反转的是获取依赖对象的方式.传统的应用在存在依赖关系时,比如A依赖于B ...
- 对Spring Ioc 以及DI的精彩理解
转:http://blog.csdn.net/cyjs1988/article/details/50352916 学习过spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注 ...
- Spring IoC与DI(依赖注入)
Spring Ioc 所谓控制反转,即将传统的需要代码进行的操作,交由Spring容器来做.下面以添加book为例进行比较一下: BookService.java public interface B ...
- 利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下
再我们现在项目中Spring框架是目前各大公司必不可少的技术,而大家都知道去怎么使用Spring ,但是有很多人都不知道SpringIoc底层是如何工作的,而一个开发人员知道他的源码,底层工作原理,对 ...
- Spring基础03——Spring IOC和DI概述
1.什么是IOC与DI IOC(Inversion of Control):其思想是反转资源获取方向,传统的资源查找方式要求组件想容器发起请求查找资源,作为回应,容器适时的返回资源,而应用了IOC之后 ...
- Spring IoC、DI入门小程序
Alt+/智能提示xml配置文件节点及属性:在接口上使用Ctrl+T可以提示其实现类 一.IoC控制反转(将创建对象的权利交给spring)入门小程序 1.引入jar包 2.工程基本结构 3.新建Us ...
随机推荐
- c# dynamic实现动态实体,不用定义实体就能序列化为标准json
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- iOS音频学习笔记一:常见音频封装格式及编码格式
(1) pcm格式 pcm是经过话筒录音后直接得到的未经压缩的数据流 数据大小=采样频率*采样位数*声道*秒数/8 采样频率一般是22k或者44k,位数一般是8位或者16位,声道一 ...
- Android 在同一台设备上安装多个同一项目的apk
如果设备上已经安装了一个apk,再次安装这个apk就会提示覆盖前面的应用 解决办法: 方法一:手动改包名 不好改,改了几次都不成功(可能是代码在svn管理的原因,改完后文件夹里的代码就没了),确实不实 ...
- JAVA笔记整理(三),JAVA中的类和方法
类 类是JAVA中一个重要的概念,可以把类理解成一个对象的抽象,这个抽象的对象包含了变量(用来描述这个对象的属性)和方法(用来描述这个对象可以干什么),类中的各个成员之间可以相互调用(static修饰 ...
- Centos7安装教程
1.下载centos7的镜像 到华为云镜像官方网站下载https://mirrors.huaweicloud.com/ 2.创建虚拟机并载入镜像 3.开启虚拟机,正式安装 选择第一项:Install ...
- MySQL 数据库的高可用性分析
MySQL数据库是目前开源应用最大的关系型数据库,有海量的应用将数据存储在MySQL数据库中.存储数据的安全性和可靠性是生产数据库的关注重点.本文分析了目前采用较多的保障MySQL可用性方案. MyS ...
- 2019-ACM-ICPC-南昌区网络赛-H. The Nth Item-特征根法求通项公式+二次剩余+欧拉降幂
2019-ACM-ICPC-南昌区网络赛-H. The Nth Item-特征根法求通项公式+二次剩余+欧拉降幂 [Problem Description] 已知\(f(n)=3\cdot f(n ...
- _MyBatis3-topic06.07.08.09_ 全局配置文件_引入dtd约束(xml提示)/ 引入properties引用/ 配置驼峰命名自动匹配 /typeAliases起别名.批量起别名
MyBatis3 的全局配置文件 : Setting -官方文档 笔记要点 出错分析 [Intellij idea配置外部DTD文件] 设置步骤: (同Eclipse中的Catalog设置 ) Fil ...
- jquery头部高亮显示方法
做网站都有头部导航栏,但导航栏的高亮显示一般都是后台技术人员做传参判断来显示高亮样式,今天来教大家一个用jquery来显示 废话不多说,直接上代码 第一步,在需要的页面中写入 <input ty ...
- CSP模拟赛 Lost My Music(二分,可回退化栈)
题面 题解 发现是斜率的形式,答案的相反数可以看做一条直线的斜率.那么我们要答案最小,斜率最大.维护下凸壳就行了. 考试时写了直接dfsdfsdfs+暴力弹栈拿了808080分(还以为自己是O(n)正 ...