手记

简单理解Spring IOC和DI

一、概念

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与配置程序运行结果相同,

2人推荐
随时随地看视频
慕课网APP