Spring的IOC/DI

本文介绍了控制反转(IOC)和依赖注入(DI)的概念,展示了如何在Spring框架中运用这两种技术来实现对象间的解耦。通过实例和代码,探讨了父子容器的区别,以及如何通过XML配置和注解实现Bean的依赖关系管理。

IOC/DI概述

依赖对象与被依赖对象

如:

class A{
}
class B{
	A a = new A();
}
  1. 这里,B中有一个A对象,当类A被删除,B就不能正常运行,所以A,B之间具有依赖关系(即B依赖于A),可以说:当一个类B中引用了另一个类A的对象,则B依赖于A
  2. 在这个例子中,B称为被依赖对象,A称为依赖对象

IOC

Inverse of Controll(控制反转)

  1. 控制即控制了类的实例化及属性的赋值(IOC容器控制了对象的创建),
  2. 所谓反转,就是将类的实例化及属性的赋值交由第三方容器(如spring、guice)(通过new关键字主动创建依赖对象为正转,反转则是由ioc容器找到依赖对象并将它注入到被依赖对象中,被依赖对象是被动的接受依赖对象)

DI

Dependence Inject(依赖注入):实现IOC的手段

IOC和DI虽然本质上都是为了解耦,但IOC和DI不完全相同,IOC是一种面向对象的编程思想,目的是解耦;而DI是实现IOC的一种手段,还有其他手段如依赖查找

父子容器(SpringMVC的配置原理)

子容器的Bean可以引用父容器中的Bean,父容器的Bean不能引用子容器中的Bean,理解起来有点类似类的继承,子类对象可以调用父类中的方法,但父类对象不能调用子类重写的方法

代码演示

类一:

public class One {
    private Two two;

    public Two getTwo() {
        return two;
    }

    public void setTwo(Two two) {
        this.two = two;
    }
}

类二:

public class Two(){}

One依赖于Two
容器一:

<?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="one" class="com.container.One">
        <property name="two" ref="two"/>
    </bean>
</beans>

容器二:

<?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="two" class="com.container.Two"/>
</beans>

测试:

@Test
    public void test1(){
        GenericXmlApplicationContext context2 = new GenericXmlApplicationContext();
        context2.load("two.xml");
        context2.refresh();
        GenericXmlApplicationContext context1 = new GenericXmlApplicationContext();
        context1.load("one.xml");
        context1.setParent(context2);//将context2设为context1的父容器
        context1.refresh();
        One one = context1.getBean("one",One.class);
        System.out.println(one.getTwo());
    }

context1中的bean引用了context2中的bean,这里将context2设为context1的父容器,context1可以访问到context2中

Test
    public void test2(){
        GenericXmlApplicationContext context1 = new GenericXmlApplicationContext();
        context1.load("one.xml");
        context1.refresh();
        GenericXmlApplicationContext context2 = new GenericXmlApplicationContext();
        context2.load("two.xml");
        context2.setParent(context1);
        context2.refresh();
        One one = context1.getBean("one",One.class);
        System.out.println(one.getTwo());
    }

这里将context1设置为context2的父容器,运行时会报错:one.xml中不存在bean:two

创建实例

实例名称

  1. id:id为bean的唯一标识
  2. name+class:可以使用逗号取多个名字(一个名字只能对应一个bean,但一个bean可以有多个名字)
  3. 匿名:默认的名字为—类全名#0,原型bean末尾数字递增;使用注解未指定名称时默认名称是类首字母小写后的类名

作用域

scope属性具有两个值:singleton和prototype

  1. singleton:单例对象,每一个bean只对应一个实例对象,在配置文件加载时实例化
  2. prototype:原型对象,每一个bean对应多个实例对象,在getBean被调用时实例化

depends-on、lazy-init

  1. depands-on:容器中的bean本是互不相干的,他们的创建没有先后顺序,但当某一个bean依赖于另一个bean时,需要控制他们实例化的顺序,就需要用到depends-on
  2. lazy-init:也是用来控制实例化时间,将lazy-init设为true则该bean将延迟加载,即当getBean的时候才会实例化,有“懒加载”的意味

init-method/destory-method

在bean初始化和销毁的时候的回调方法,应用场景少
destory-method一个常用场景是对于数据源的bean销毁时关闭连接

parent、abstract

在多个bean具有相同的内容时可以使用一个公共bean,并将abstract设为true,其他标签的parent指向该公共bean即可,可以简化开发 ,提高可维护性

注解

  1. @Component:一般组件,用于修饰普通类
  2. @Service:用于修饰业务逻辑层
  3. @Respository:用于修饰dao层
  4. @Controller:用于修饰控制器
  5. @Scope:同xml中的scope属性

注入属性

xml写法一

xml写法二(命名空间)

  1. p:用于为bean的属性赋值
<bean id="demo2" class="com.propertyInject.Demo2"/>
<bean id="demo1" class="com.propertyInject.Demo1" p:id="1" p:name="张三" p:demo2-ref="demo2"/>

id,name,demo2为Demo1的属性

<bean id="demo2" class="com.propertyInject.Demo2" p:names="1,2,3"/>

对于数组,直接用逗号隔开即可

  1. c:用于为bean的构造方法传参数
<bean id="demo11" class="com.propertyInject.Demo1" c:id="1" c:name="张三" c:demo2-ref="demo2"/>
  1. util:用于单独定义集合,映射,属性
<bean id="demo22" class="com.propertyInject.Demo2" p:names="1,2,3" p:ages-ref="ages" p:codes-ref=""></bean>
    <util:list id="ages">
        <value>10</value>
        <value>20</value>
        <value>30</value>
    </util:list>
    <util:map id="codes">
        <entry key="code1" value="1"/>
    </util:map>

注解写法

  1. @Value:注入简单类型,直接赋值;并不适合直接写死赋值,而是引用外部属性文件来获取值

xml配置方法:使用<context:property-placeholder location="<!--properties文件路径-->"配置属性文件,然后通过${}的方式在注解中获取值

注解配置方法:使用@PropertySource注解指定属性文件路径,然后在类中使用@Autowired private Enviroment env;使用env.getProperty(“name”)来获取属性文件的值

  1. @Autowired:先找类型,如果在容器中该类型只有一个bean,则将该bean注入;如果在容器中该类型有多个bean,则根据该属性的名称来找到相同名称的bean,没有则报错
  2. @Resource:无视类型,通过属性名在容器中找到相同名称的bean然后注入,属性不匹配或找不到则报错
  3. @Qualifier:配合@Autowired使用,当同类型有多个bean时,可以不修改属性名,而是通过该注释来指定需要注入的bean
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值