一、概念
IOC:Ioc—Inversion of Control,控制反转。IOC主要是一种设计思想。在应用程序中,原本由程序主动去new依赖对象,变成了由IOC容器来控制对象的创建。所以,所谓的控制反转,控制指的是IOC容器控制了对象的创建,反转指的是程序依赖IOC容器来注入对象。
DI:Dependency Injection,依赖注入。组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
----------------------------------------------------------------------------------------
谁依赖于谁:当然是应用程序依赖于IoC容器;
为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
摘抄自CSDN: https://blog.csdn.net/qq_22654611/article/details/52606960/
-----------------------------------------------------------------------------------------
明确IOC和DI的关系:其实它们是同一个概念的不同角度描述
一个对象的创建往往会涉及到其他对象的创建,比如一个对象A的成员变量持有着另一个对象B的引用,这就是依赖,A依赖于B。IOC机制既然负责了对象的创建,那么这个依赖关系也就必须由IOC容器负责起来。负责的方式就是DI——依赖注入,通过将依赖关系写入配置文件,然后在创建有依赖关系的对象时,由IOC容器注入依赖的对象,如在创建A时,检查到有依赖关系,IOC容器就把A依赖的对象B创建后注入到A中(组装,通过反射机制实现),然后把A返回给对象请求者,完成工作。
二、实例
1、容器通过配置的xml获取对象:
首先创建一个spring项目,在src目录下创建HelloWorld实体类,代码如下:
public class HelloWorld { private String hello; public void setHello(String hello){ this.hello = hello; } public void sayHello(){ System.out.println(this.hello); } }
其次在spring的配置xml(此处我自己在src目录下创建的IOC.xml)文件中,添加bean,代码如下:
其中每个bean的id是其在容器中的标识,class是实体类的具体路径,property配置对象的属性值
<?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.xsd"> <bean id="hello" class="HelloWorld"> <property name="hello" value="HelloWorld"></property> </bean> </beans>
之后创建TestIOC ,测试代码如下:
context就是一个IOC容器,它从配置的IOC.xml获取对象资源,并提供给主程序。
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestIOC { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("IOC.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("hello"); helloWorld.sayHello(); } }
2、获取依赖对象:
在原项目src目录下新建Student类,代码如下:
public class Student { private String name; public Student(){} public String getName() { return name; } public void setName(String name) {this.name = name; } public void sayName(){ System.out.println(this.getName()); } }
修改HelloWorld,代码如下:
public class HelloWorld { private String hello; private Student student; public HelloWorld(){ } public void setStudent(Student student){ this.student = student; } public Student getStudent() { return student; } public String getHello() { return hello; } public void setHello(String hello){ this.hello = hello; } public void sayHello(){ System.out.println(this.hello); } }
修改IOC.xml代码如下:(构造器方式注入不常用,可自行度娘,此处为设值注入)
<?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.xsd"> <bean id="student" class="Student"> <property name="name" value="ccc"></property> </bean> <bean id="hello" class="HelloWorld"> <property name="hello" value="helloWorld"></property> <property name="student" ref="student"></property> </bean> </beans>
测试TestIOC:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestIOC { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("IOC.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("hello"); helloWorld.sayHello(); System.out.println(helloWorld.getStudent().getName()); } }
运行结果
信息: Loading XML bean definitions from class path resource [IOC.xml] helloWorld ccc
此时,Student类作为HelloWorld类的依赖对象,所以在创建HelloWorld对象时,IOC容器就把创建Student对象并注入到HelloWorld对象中,就是前面提到的依赖注入。
那么问题来了,如果对于每一个实体类,都要通过配置bean去实现IOC,还相较于直接new来说,开发效率并没有多大的提升,下面提供通过注解的方式去实现实体类的bean配置:
首先开启spring对注解的识别,在IOC.xml添加,注意头文件有改动,代码如下:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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-3.0.xsd"> <context:annotation-config></context:annotation-config> <bean id="student" class="Student"> <property name="name" value="ccc"></property> </bean> <bean id="hello" class="HelloWorld"> <property name="hello" value="helloWorld"></property> <!-- <property name="student" ref="student"></property> --> <!--<constructor-arg name="student" ref="student"></constructor-arg> 构造器注入,要求有相应构造函数,参数一致 --> </bean> </beans>
接下来只需要修改HelloWorld,在student属性前添加@Autowired注解,也可以在setStudent方法前添加@Autowired,效果相同,代码如下:
import org.springframework.beans.factory.annotation.Autowired; public class HelloWorld { private String hello; @Autowired private Student student; public HelloWorld(){ } public HelloWorld(Student student) { this.student = student; } public void setStudent(Student student){ this.student = student; } public Student getStudent() { return student; } public String getHello() { return hello; } public void setHello(String hello){ this.hello = hello; } public void sayHello(){ System.out.println(this.hello); } }
此外也可以使用@Resource(name=“bean id”)的形式来达到相同的效果,代码如下:
import javax.annotation.Resource; public class HelloWorld { private String hello; @Resource(name="student") private Student student; public HelloWorld(){ } public HelloWorld(Student student) { this.student = student; } public void setStudent(Student student){ this.student = student; } public Student getStudent() { return student; } public String getHello() { return hello; } public void setHello(String hello){ this.hello = hello; } public void sayHello(){ System.out.println(this.hello); } }
这样还不够高效,我们还有更简单的实现方法!在IOC.xml下只保留以下代码,意为自动扫描com.IOC.pojo下的类
<context:component-scan base-package="com.IOC.pojo"/>
一开始忘记建包了,emmm,建包com.IOC.pojo 将实体类移入
代码如下:
IOC.xml:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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-3.0.xsd"> <context:component-scan base-package="com.IOC.pojo"></context:component-scan> </beans>
HelloWorld.java: 添加注解@Component("hello"),student属性前@Autowired,然后为hello赋初值
package com.IOC.pojo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Resource; @Component("hello") public class HelloWorld { //注意设置初始值 private String hello ="hello"; //@Resource(name="student") @Autowired private Student student; public HelloWorld(){ } public HelloWorld(Student student) { this.student = student; } public void setStudent(Student student){ this.student = student; } public Student getStudent() { return student; } public String getHello() { return hello; } public void setHello(String hello){ this.hello = hello; } public void sayHello(){ System.out.println(this.hello); } }
Student.java: 添加注解@Component("student"),然后为name赋初值
package com.IOC.pojo; import org.springframework.stereotype.Component; @Component("student") public class Student { //注意设置初值 private String name="ccc"; public Student(){ } public String getName() { return name; } public void setName(String name) { this.name = name; } public void sayName(){ System.out.println(this.getName()); } }
TestIoc.java:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.IOC.pojo.*; public class TestIOC { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("IOC.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("hello"); helloWorld.sayHello(); System.out.println(helloWorld.getStudent().getName()); } }
以上通过注解实现IOC与配置程序运行结果相同,