欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring学习之IOC和DI

程序员文章站 2022-06-22 16:06:34
...

首先我想明确它们之间的关系:

  • IOC:控制反转,把创建对象的过程交给Spring去管理,自己不做任何关注。
  • DI:依赖注入,向Bean里的属性进行设值。
  • DI是不可以自己独立进行工作的,必须要在IOC的基础上完成工作,也可以理解为DI是IOC的一种实现。

什么是IOC?

  • 首先我想谈一下我自己的想法

IOC全名是Inverse Of Control,意思是控制反转,那么这个控制反转到底是什么意思呢?通俗一点可以这样子理解:众所周知,在java程序中,完成每个业务逻辑必须至少需要两个或以上的对象来协助完成。在传统编程中,假设我的程序中存在两个对象A和B,当A需要B的一些帮助,我们必须去手动实例化这个对象(类似new object()这样子的语法),而IOC的思想是:我们可以把对象之间的引用关系交给Spring来管理,对象的创建、维护、销毁等生命周期的这些操作程序人员完全不用自己关注,全权交给Spring容器,其实这样就把控制权交给了Spring,所以就叫做控制反转。

  • Bean的生命周期

在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就说每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象。
Spring学习之IOC和DI

  • 注入的三种方式
    • 基于XML的bean定义(需要提供setter方法)

首先定义Student和Teacher类。

package com.demo.ioc.Bean;

public class Student {

    private String name;

    private Teacher teacher;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }


}
package com.demo.ioc.Bean;

public class Teacher {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

bean1.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="com.demo.ioc.Bean.Student">
        <property name="name" value="张三"/>
        <property name="teacher" ref="teacher"/>
    </bean>

    <bean id="teacher" class="com.demo.ioc.Bean.Teacher">
        <property name="name" value="李四"/>
    </bean>
</beans>
package com.demo.ioc.spring;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.demo.ioc.Bean.Student;
import com.demo.ioc.Bean.Teacher;

public class Main {

    public static void main(String args[]) throws Exception{
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean1.xml");
        Student student = (Student) context.getBean("student");
        Teacher teacher = (Teacher) context.getBean("teacher");
        System.out.println("学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());
        System.out.println("老师的姓名:"+teacher.getName());
    }

}
  • 基于注解的bean定义(不需要提供setter方法)
package com.demo.ioc.Bean;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("student")
public class Student {

    @Value("张三")
    private String name;

    @Resource
    private Teacher teacher;

    public String getName() {
        return name;
    }

//  public void setName(String name) {
//      this.name = name;
//  }

    public Teacher getTeacher() {
        return teacher;
    }

//  public void setTeacher(Teacher teacher) {
//      this.teacher = teacher;
//  }


}
package com.demo.ioc.Bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("teacher")
public class Teacher {

    @Value("李四")
    private String name;

    public String getName() {
        return name;
    }

//  public void setName(String name) {
//      this.name = name;
//  }

}

bean2.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--扫描组件的包目录-->
    <context:component-scan base-package="com.demo.ioc.Bean"/>

</beans>
package com.demo.ioc.spring;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.demo.ioc.Bean.Student;
import com.demo.ioc.Bean.Teacher;

public class Main {

    public static void main(String args[]) throws Exception{
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean2.xml");
        Student student = (Student) context.getBean("student");
        Teacher teacher = (Teacher) context.getBean("teacher");
        System.out.println("学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());
        System.out.println("老师的姓名:"+teacher.getName());
    }

}
  • 基于JavaConfig定义(需要提供setter方法)
package com.demo.ioc.Bean;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeansConfiguration {

    @Bean
    public Student student(){
        Student student=new Student();
        student.setName("张三");
        student.setTeacher(teacher());
        return student;
    }

    @Bean
    public Teacher teacher(){
        Teacher teacher=new Teacher();
        teacher.setName("李四");
        return teacher;
    }

}
package com.demo.ioc.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.demo.ioc.Bean.BeansConfiguration;
import com.demo.ioc.Bean.Student;
import com.demo.ioc.Bean.Teacher;

public class Main {

    public static void main(String args[]) throws Exception{
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(BeansConfiguration.class);
//        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean2.xml");
        Student student = (Student) context.getBean("student");
        Teacher teacher = (Teacher) context.getBean("teacher");
        System.out.println("学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());
        System.out.println("老师的姓名:"+teacher.getName());
    }

}
  • 容器中Bean的作用域

    • 当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下五种作用域:

      1. singleton: 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
      2. prototype: 每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
      3. request:对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
      4. session:该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
      5. global session: 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效,同样只在Web应用中有效。
  • 如何实现IOC

    • Spring IOC的实现用到了设计模式:简单工厂模式+反射来实现IoC。
  • BeanFactory和ApplicationContext的区别
    ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,最主要的就是BeanFactory延迟加载,当使用到getBean的时候才会抛异常,而ApplicationContext在刚开始启动加载的时候就会抛出异常,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。

什么是DI?

  • 全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。
  • 它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的。
  • 其实我个人觉得IOC和DI是一个东西。
public static Object newInstance(String className) {   
        Class<?> cls = null;   
        Object obj = null;   
        try {   
            cls = Class.forName(className);   
            obj = cls.newInstance();   
        } catch (ClassNotFoundException e) {   
            throw new RuntimeException(e);   
        } catch (InstantiationException e) {   
            throw new RuntimeException(e);   
        } catch (IllegalAccessException e) {   
            throw new RuntimeException(e);   
        }   
        return obj;   
    }

为什么要使用IOC?

在IOC出现以前,组件之间的协调关系是由程序内部代码来控制的,或者说,以前我们使用New关键字来实现两组间之间的依赖关系的。这种方式就造成了组件之间的互相耦合。IoC(控制反转)就是来解决这个问题的,它将实现组件间的关系从程序内部提到外部容器来管理。也就是说,由容器在运行期将组件间的某种依赖关系动态的注入组件中。