Spring中的IoC的基本概念及实现原理

本文详细介绍了Spring中的IoC(控制反转)概念,包括依赖倒置原则和依赖注入,并探讨了Spring如何通过XML和注解方式实现IoC。深入解析了BeanFactory、ApplicationContext和BeanDefinition在Spring IoC容器中的作用,以及Bean的生命周期管理。
摘要由CSDN通过智能技术生成

本文内容基于《Spring 5企业级开发实战》,周冠亚、黄文毅著。


1. IoC的概念

1.1 依赖倒置原则

1.2 依赖注入

2. Spring IoC的实现方式

2.1 XML方式

2.2 注解方式

3. Spring IoC实现原理解析

3.1 BeanFactory代码解析

3.2 ApplicationContext代码解析

3.3 BeanDefinition代码解析

3.4 Spring IoC代码分析

4. Spring IoC容器中的Bean的生命周期


1. IoC的概念

IoC是Inversion of Control的简写,即控制反转。IoC并不是一门技术,而是一种设计思想。

在没有IoC设计的场景下,开发人员在使用所需的对象时,需手动创建各种对象,如new Student()。

有了IoC这样的设计思想,在开发中,意味着将设计好的对象交给容器管理,而不再是像传统的编程方式中,在对象内部直接控制对象。

在传统Java程序设计中,直接在某个对象内部new创建另一个对象,这是开发人员主动去创建依赖对象;IoC的设计思想是通过专门的对象容器来创建和维护对象;即对象由开发人员控制 -> 对象由容器来控制

1.1 依赖倒置原则

抽象不应该依赖于具体实现,具体实现应该依赖于抽象

【实例】

一个人,需要通过某种交通工具去上班。

  • 不遵循依赖倒置原则的设计风格:
public class Person {

    /*private class Bike {
        public void go() {
            System.out.println("bike go");
        }
    }*/

    private class Car {
        public void go() {
            System.out.println("car go");
        }
    }

    /**
     * 自行车
     */
    //private Bike bike;

    /**
     * 小车
     */
    private Car car;

    /**
     * 创建人的时候为他创建自行车/小车
     */
    public Person() {
        //this.bike = new Bike();
        this.car = new Car();
    }

    /**
     * 上班
     */
    public void goWork() {
        //bike.go();
        car.go();
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        person1.goWork();
    }
}

上述代码表达了这个人如果从骑自行车上班变为开车上班,需要对代码进行重构,意味着每一次更改都需要重构。

  • 遵循依赖倒置原则的设计风格:
public class Person {

    private interface Movable {
        void go();
    }

    private class Bike implements Movable {
        @Override
        public void go() {
            System.out.println("bike go");
        }
    }

    private class Car implements Movable {
        @Override
        public void go() {
            System.out.println("car go");
        }
    }

    /**
     * 交通工具
     */
    private Movable movable;

    /**
     * 创建人的时候为他创建交通工具
     */
    public Person() {
        //this.movable = new Bike();
        this.movable = new Car();
    }

    /**
     * 上班
     */
    public void goWork() {
        movable.go();
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        person1.goWork();
    }
}

以上代码表达了,将自行车、小车抽象成交通工具,如果要换交通工具只需要修改一句代码就行了。

1.2 依赖注入

上述代码遵循了依赖倒置,可以发现其中的Bike或是Car还是需要开发人员主动去创建,这时候就可以应用IoC的思想,让依赖关系由容器来管理。

依赖注入(DI,Dependency Injection)是Spring实现IoC的容器的一种重要手段:

@Component
public class Person {

    private interface Movable {
        void go();
    }

    @Component("bike")
    private class Bike implements Movable {
        @Override
        public void go() {
            System.out.println("bike go");
        }
    }

    @Service("car")
    private class Car implements Movable {
        @Override
        public void go() {
            System.out.println("car go");
        }
    }

    /**
     * 交通工具
     */
    //@Resource(name = "bike")
    @Resource(name = "car")
    private Movable movable;

    /**
     * 上班
     */
    public void goWork() {
        movable.go();
    }
}

因为需要IoC容器进行依赖注入,所以这里就不能用main方法来测试了,必须在Spring上下文中,创建单元测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonTest {

    @Autowired
    Person person;

    @Test
    public void goWork() {
        person.goWork();
    }
}

【注】IoC容器中存放的是单例模式的对象

【理一下控制反转、依赖倒置、依赖注入的关系】控制反转是一种软件设计模式,其遵循了软件工程中的依赖倒置原则,而依赖注入是Spring实现控制反转的一种方式

2. Spring IoC的实现方式

2.1 XML方式

public interface Movable {
    void go();
}
public class Bike implements Movable {

    public Bike() {
    }

    @Override
    public void go() {
        System.out.println("bike go");
    }
}
public class Car implements Movable {

    private String name;

    public Car(String name) {
        this.name = name;
    }

    @Override
    public void go() {
        System.out.println(name + " car go");
    }
}
public class Person {

    /**
     * 交通工具
     */
    //@Resource(name = "bike")
    @Resource(name = "car")
    private Movable movable;

    /**
     * 上班
     */
    public void goWork() {
        movable.go();
    }
}
<!--?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="bike" class="com.yeta.review.c.Bike" />

    <!--有参构造-->
    <bean id="car" class="com.yeta.review.c.Car">
        <constructor-arg index="0" value="BMW" />
    </bean>

    <bean id="person" class="com.yeta.review.c.Person" />

</beans>
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration("classpath:spring-ioc.xml")
public class PersonTest {

    @Autowired
    Person person;

    @Test
    public void goWork() {
        person.goWork();
    }
}

2.2 注解方式

注解方式与1.2中代码一致,这里区分一下几个注解:

  • @Component:将Java类标记成一个Spring Bean组件;
  • @Service:将业务层实现类标记成一个Spring Bean组件;
  • @Controller:将控制层类标记成一个Spring Bean组件;
  • @Repository:将持久层实现类标记成一个Spring Bean组件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值