Spring IOC理论

2.IOC理论

2.1 IOC理论推导
  • 在之前的业务中,用户需求的变化会导致原有的业务代码,需要根据用户的需求来修改源代码,程序代码量庞大,修改一次成本太昂贵。
UserDao/UserDaoImpl/UserOhterSqlDaoImpl
UserService/UserServiceImpl
UserServiceImpl{
	UserDao userDao = new UserDaoImpl(); //这种对象实例方式会用户的调佣不同而经常修改
	UserDao = new UserOhterSqlDaoImpl();
}
//所以创建对象不该由这里的service去决定,而是从外界传入,让调用方去实例实现对象,传入本方法中,从而保证代码不用修改也能做到适应

  • 用一个set方法去适应,使用set注入后程序不具有主动性,变成了被动的接受对象

在调用service方法是注意:有强转现现象,子类自己的方法,不能通过父类变量调用,即多态父类使用子类独有的方法要强转

UserDao userDao = null;
public void setUserDao(UserDao userDao){
	this.userDao = userDao
}

TiP:在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。

但在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,其大致步骤如下。

  1. 开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用 标签、在 Java 类上使用 @Component 注解等。
  2. Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。
  3. 当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。
  • IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Bean),使系统耦合性降低,让开发更加专注业务的实现,这就是IOC的原型
  • 这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。

设计模式的本质不是为了消除变化,而是为了将变化集中在一个地方

  • IOC解耦的过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vhyt5P6T-1656508419443)(../typora-user-images/image-20220621134949953.png)]

2.2 IOC本质
  • Spring IoC的全称是Inversion of Control,称为控制反转,是一种思想,DI(依赖注入)是实现Ioc的一种方法。
  • IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
  • 传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

控制反转:核心思想就是由 Spring 负责对象的创建。在对象创建过程中,Spring 会自动根据依赖关系,将它依赖的对象注入到当前对象中,这就是所谓的“依赖注入”。

  • IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
  • Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2AVYNEl-1656508419444)(../typora-user-images/vjoqi0qk.iju.jpg)]

  • 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
  • 控制反转是通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在spring中实现控制反转是IOC容器,实现方法是依赖注入DI(Dependency Injection)
2.3 举例理解
  • 实体类
public class Hello {
    private String message;

    public Hello() {
    }

    public Hello(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {return false;}

        Hello hello = (Hello) o;

        return message != null ? message.equals(hello.message) : hello.message == null;
    }

    @Override
    public int hashCode() {
        return message != null ? message.hashCode() : 0;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "message='" + message + '\'' +
                '}';
    }
}
  • spring配置文件
<?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">

   <!--使用spring来创建对象,在spring这些都称为bean
    相当于new对象
    id ==对象名
    class== 对象类型
    property:set属性
    message:set方法中的参数名
    -->
    <bean id="hello" class="com.zk.pojo.Hello">
        <!--value:具体的值,基本数据类型
        ref:引用spring容器中已经创建好的值 -->
        <property name="message" value="hello zk!"/>
    </bean>

</beans>
  • 调用
@Test
public void TestDemo01(){
    //获取spring的ApplicationContext上下文对象,即spring容器
    //参数可以传多个
    //解析bean.xml文件,生成管理相应的bean对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Beans.xml");
        //getBean:参数为spring配置文件中bean的id
        //这里不强转,也可以在第二个参数传入类型,类似mybatis
       //**id前添加&获取工厂
    Hello hello = applicationContext.getBean("hello", Hello.class);
    System.out.println(hello.getMessage());
}
  • 结果
hello zk!

注意存在的问题:

xml依赖注入arg是通过构造函数,property是通过seter方法,name属性要和实体类的属性名一致

spring容器调用无参构造器创建队像,然后用set注入,所以实体类需要无参构造器。若没有无参构造,容器通过反射创建对象(Class对象的newInstance()方法默认调用的是无参构造)会失败

没spring托管叶子:XML顶部的警告:配置上下文
在这里插入图片描述


在这里插入图片描述

  • 类单继承,接口多继承,但是由于jdk8中接口可以使用default关键字具体实现方法,所以实际上实现多个接口可能会出现类的多继承的效果
public interface Trst {
    default void test() {
        System.out.println("方法体");
    }
}
  • 区别就是需求变更后只需要在配置文件中改一次,不需要到处在别的类的代码中修改,改源代码需要重新发布项目,后续这些配置会放到统一的配置中心去,类似一个后台。在线修改后,运行中的项目会直接热加载,即时生效。

改配置文件需要需要知道加载机制是热加载还是冷加载

  • 依赖注入:property利用set方法进行注入,所以实体类必须有这个属性的构造方法
<property name="message" value="hello zk!"/>
  • 若想进一步了解这个容器创建bean的实现可以浏览下ClassPathXmlApplicationContext类的源码
本专栏下一篇:Spring IoC 使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值