spring之IoC、Di

目录

1、spring IoC的基本概念

1.1、什么是IoC(控制反转)

1.2、什么是Di(依赖注入)

1.3、对于依赖注入方式的一个小栗子:

1.3.1、依赖注入器

1.3.2、三个测试对象  、粗略一看即可

1.3.3、测试类 

1.3.4、结果

1.3.5、小结

2、 Spring IoC 容器 及其 依赖注入的类型

2.1 BeanFactory 容器

2.2 ApplicationContext 容器

2.3 依赖注入的类型

2.4、栗子:bean容器的简单使用及各种注入方式的示例

2.4.1、 xml配置

2.4.2、 测试类及结果

2.4.3、 简单类 

2.4.4、小结

3、参考资料


1、spring IoC的基本概念

1.1、什么是IoC(控制反转)

在通常的做法中,我们会在需要的时候直接用new关键字创建一个对象,此时对象的创建是由我们调用者直接控制并管理。而控制反转(ioc)则是把对象实例的创建及管理交付给第三方,对象实例的控制权不再属于调用者,当调用者需要调用某一实例时,需向第三方请求,由第三方将实例交付给调用者。

1.2、什么是Di(依赖注入)

控制反转是一个大的概念,而依赖注入(DI)则是ioc的实现方式,依赖是个名词,是指被依赖的对象,即调用者请求的对象实例,注入则是把这个对象实例(依赖)给注入到调用者所声明的变量中。

例如这个简图,在传统的做法中,当我们需要调用B类时,是通过new关键字直接创建实例,但在这种做法中我们必须自己选择B类的实现类(如果是多实现类),这种直接创建实例的方式会使A类和B类的耦合度非常高,降低A的可重用性。而在使用依赖注入时,我们是在与第三方容器打交道,通过它来获取实例,此时我们并不知道此实例来自哪里,但我们并不用关心,我们只知道这个实例能够提供我们所需的功能即可,这种做法极大的降低了依赖者(A类)和被依赖者(B类)的耦合度,更有利于程序的可扩展性。这个模式就是依赖注入,也即是控制反转。

1.3、对于依赖注入方式的一个小栗子:

1.3.1、依赖注入器


import java.util.HashMap;
import java.util.Map;

public class DependencyInjector {
    private final Map<Class ,Object> singleton = new HashMap<>();  //这样实现单例是不妥的,我只是方便使用
    private boolean isSingleton = true; //默认单例模式

    public DependencyInjector(boolean isSingleton) {
        this.isSingleton = isSingleton;
    }

    public Object getBean(Class clazz) throws Exception {
        if (clazz == A.class)
            return createA();
        else if(clazz == B.class)
            return createB();
        else if( clazz == C.class)
            return createC();
        else{
            throw new Exception("只支持这三种类型");
        }
    }

    //这里应该是bean工厂,例子简单实现
    private B createB(){
        if (isSingleton){  //如果是单例模式
            if (singleton.containsKey(B.class)){  //如果已存在实例,注意这不是线程安全的
                return (B)singleton.get(B.class);
            } else {
                B b = new B();
                b.setC(createC());
                singleton.put(B.class,b);
                return b;
            }
        } else {
            B b = new B();
            b.setC(createC());
            return b;
        }
    }
    private A createA(){
        if (isSingleton){
            if (singleton.containsKey(A.class)){
                return (A)singleton.get(A.class);
            } else {
                A a = new A();
                a.setB(createB());
                singleton.put(A.class,a);
                return a;
            }
        } else {
            A a = new A();
            a.setB(createB());
            return a;
        }
    }
    private C createC(){
        if (isSingleton){
            if (singleton.containsKey(C.class)){
                return (C)singleton.get(C.class);
            } else {
                C c = new C();
                singleton.put(B.class,c);
                return c;
            }
        } else {
            C c = new C();
            return c;
        }
    }
}

1.3.2、三个测试对象  、粗略一看即可

public class A {
    private B b;

    public void setB(B b) {
        this.b = b;
    }
    @Override
    public String toString() {
        return "A{这是A,依赖于B " +
                "b=" + b +
                '}';
    }
}
public class B {
    private C c;

    public void setC(C c) {
        this.c = c;
    }

    @Override
    public String toString() {
        return "B{这是B,依赖于C " +
                "c=" + c +
                '}';
    }
}
public class C {

    @Override
    public String toString() {
        return "C{这是C:没有依赖}";
    }
}

1.3.3、测试类 

public class Test {
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        DependencyInjector di = new DependencyInjector(true);
        A a = (A) di.getBean(A.class);
        A a1 = (A) di.getBean(A.class);
        System.out.println(a == a1);
        System.out.println(a);
        B b = (B) di.getBean(B.class);
        System.out.println(b);
        C c = (C) di.getBean(C.class);
        System.out.println(c);
    }
}

1.3.4、结果

是否来自同一个实例:true
A{这是A,依赖于B b=B{这是B,依赖于C c=C{这是C:没有依赖}}}
B{这是B,依赖于C c=C{这是C:没有依赖}}
C{这是C:没有依赖}

1.3.5、小结

通过依赖注入器DependencyInjector 类 我们可以不再自己创建A、B、C类,而是从依赖注入器中获取,从而降低了调用者与A、B、C类的耦合度。同时DependencyInjector(及所有依赖注入框架)的魅力在于,他所返回的对象也和依赖一同被注入了,如果某一个依赖中还有其他的依赖,那么这个依赖也会随之一起被注入

 

2、 Spring IoC 容器 及其 依赖注入的类型

在spring中,ioc的思想贯穿整个框架,而实现ioc的是spring ioc容器,实现的方式就是依赖注入。 

在spring中ioc服务的主要有 org.springframework.beans.factory.BeanFactionorg.springframework.context.ApplicationContext 这两个接口提供的

2.1 BeanFactory 容器

这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactory 中被定义。

在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。

2.2 ApplicationContext 容器

Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文。 Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 
ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。
最常被使用的 ApplicationContext 接口实现:
• FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
• ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
• WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

2.3 依赖注入的类型

依赖注入的类型有:setter注入,集合注入,构造注入,接口注入

2.4、栗子:bean容器的简单使用及各种注入方式的示例

2.4.1、 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="person" class="ioc.testBeanFactory.Person">

        <property name="x" value="1"></property> <!--  setter 注入 -->
        
        <property name="list" >   <!--  集合注入 -->
            <list>
                <value>1</value>
                <value>1</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="ioc" value="nice"></entry>
            </map>
        </property>
        <property name="set">
            <set>
                <value>ssd</value>
                <value>kjkj</value>
            </set>
        </property>

        <!-- 注意这个是引用  -->
        <property name="cat" ref="catId"></property>
    </bean>
    <!--   -->
    <bean name="catId" class="ioc.testBeanFactory.Cat">
        <!-- 构造注入 index为构造构造方法参数的索引 注意,bean默认注入无参构造方法,若类中无提供无参构造方法,则必须注入有参构造方法  -->
        <constructor-arg index="0" value="2"/>
    </bean>
</beans>

2.4.2、 测试类及结果

package ioc.testBeanFactory;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;

public class Test {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //这种方式并不常用
        BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D:\\program\\IdeaProjects\\dongruan\\springIoc\\src\\application.xml"));
        Person person = (Person) beanFactory.getBean("person");
        person.print();

        ApplicationContext context;
        context = new FileSystemXmlApplicationContext("D:\\program\\IdeaProjects\\dongruan\\springIoc\\src\\application.xml");
        person = (Person) context.getBean("person");
        person.print();

       // context = new ClassPathXmlApplicationContext("file:D:\\program\\IdeaProjects\\dongruan\\springIoc\\src\\application.xml");
       // context = new ClassPathXmlApplicationContext("classpath:application.xml");
        context = new ClassPathXmlApplicationContext("application.xml");
        person = (Person) context.getBean("person");
        person.print();
    }
}

//----- 结果

spring ioc test
Person{x=1, list=[1, 1], set=[ssd, kjkj], map={ioc=nice}, cat=Cat{cat=2}}
spring ioc test
Person{x=1, list=[1, 1], set=[ssd, kjkj], map={ioc=nice}, cat=Cat{cat=2}}
spring ioc test
Person{x=1, list=[1, 1], set=[ssd, kjkj], map={ioc=nice}, cat=Cat{cat=2}}

2.4.3、 简单类 

package ioc.testBeanFactory;

public class Cat {
    private  int cat;

    public Cat(int cat) {
        this.cat = cat;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "cat=" + cat +
                '}';
    }
}

package ioc.testBeanFactory;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Person {
    private int x;
    private List<Integer> list;
    private Set<String> set;
    private Map map;
    private Cat cat;


    void print(){
        System.out.println("spring ioc test");
        System.out.println(this.toString());
    }

//-------省略setter方法-----------


    @Override
    public String toString() {
        return "Person{" +
                "x=" + x +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", cat=" + cat +
                '}';
    }
}

2.4.4、小结

采用绝对路径的加载方式将导致程序的灵活性变差,一般不推荐使用。因此, 通常在Spring 的Java 应用中采取通过ClassPathXmlApplicationContext 类来实例化ApplicationContext 容器的方式,而在Web 应用中, ApplicationContext 容器的实例化工作将交给Web 服务器完成,使用WebXmlApplicationContext类。 

在使用各种注入方式时;使用setter注入需要实现类提供setter方法,但此实现类必须提供无参构造方法,当实现类没有提供无参构造方法,则必须使用构造注入方式,使用构造注入时,最好添加索引,即使用index来显示此依赖是注入到构造方法的第几个参数上。第一个参数的index为0。

3、参考资料

 https://blog.csdn.net/bestone0213/article/details/47424255

https://www.w3cschool.cn/wkspring/yqdx1mm5.html

《servlet和jsp学习指南》.((加)Budi Kurniawan)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值