002-Spring Ioc入门

什么是Ioc

IoC 也称为依赖注入 (DI)又名控制反转。Ioc是一个过程,可以有以下方式来实现。

  • 接口注入:接口注入基于接口将调用与实现分离。这种依赖注入方式必须实现容器所规定的接口,使程序代码和容器的API绑定在一起,这不是理想的依赖注入方式。Spring不支持这种方式的依赖注入.
  • Setter方式注入:基于JavaBean的Setter方法为属性赋值。在实际开发中得到了广泛应用。
  • 构造器注入:基于构造方法为属性赋值。容器通过调用类的构造方法,将其所需的依赖关系注入其中。

基本依赖

org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基础。由于我们的Spring Boot HelloWorld 使用了spring-boot-starter-web,其包含了这两个依赖,所以我们可以不再添加这两个依赖。

Ioc容器

org.springframework.context.ApplicationContext接口代表 Spring IoC 容器,负责实例化、配置和组装 bean。

独立应用程序中ApplicationContext实例化

Spring 提供了ApplicationContext接口的几种实现。在独立应用程序中,通常使用如下两种方式

  • ClassPathXmlApplicationContext:读取类的根路径的xml配置(spring Boot中resource目录即为类的根路径)
  • FileSystemXmlApplicationContext:通过文件实际路径来读取xml配置。
    其继承结构图如下:
    在这里插入图片描述

web应用程序中ApplicationContext实例化

在web.xml中声明如下配置即可:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  • 侦听器检查contextConfigLocation参数。如果该参数不存在,则侦听器将/WEB-INF/applicationContext.xml用作默认值。
  • 当参数确实存在时,侦听器String通过使用预定义的分隔符(逗号、分号和空格)来分隔参数。
  • 也支持 *号匹配
    • /WEB-INF/*Context.xml(在WEB-INF目录中所有以Context.xml结尾的xml文件)
    • /WEB-INF/**/*Context.xml (在WEB-INF目录及其子目录中所有以Context.xml结尾的xml文件)

容器中bean的配置方式

容器通过读取配置元数据来获取有关要实例化、配置和组装哪些对象的指令。配置元数据有以下3种方式配置:

  • XML配置:将Bean的所以依赖配置都放在xml配置文件中配置
  • Java 注解配置:Spring 2.5 引入了对基于注解的配置元数据的支持。@Component、@Autowired等
  • Java 代码配置:从 Spring 3.0 开始,可以使用代码配置。因此,我们可以使用 Java 而不是 XML 文件来定义应用程序类外部的 bean。@Configuration, @Bean, @Import,和@DependsOn等注释

xml配置

首先创建一个简单的Bean对象Emp

package com.yyoo.boot.bean;

import java.util.Date;

public class Emp {

    private Long empNo;

    private String eName;

    private String job;

    private Long mgr;

    private Date hiredate;

    private Double sal;

    private Double comm;

    private Long deptno;

    public Emp(){}

    public Emp(Long empNo, String eName, String job, Long mgr, Date hiredate, Double sal, Double comm, Long deptno) {
        super();
        this.empNo = empNo;
        this.eName = eName;
        this.job = job;
        this.mgr = mgr;
        this.hiredate = hiredate;
        this.sal = sal;
        this.comm = comm;
        this.deptno = deptno;
    }


    /**
     * 工厂静态方法注入
     * @return
     */
    public static Emp newInstance(){
        Emp emp = new Emp();
        emp.setEmpNo(1000L);
        emp.setEName("工厂静态方法注入");
        return emp;
    }

    /**
     * 工厂实例方法注入
     * @return
     */
    public Emp getInstance(){
        Emp emp = new Emp();
        emp.setEmpNo(1001L);
        emp.setEName("工厂实例方法注入");
        return emp;
    }


    public Long getEmpNo() {
        return empNo;
    }

    public void setEmpNo(Long empNo) {
        this.empNo = empNo;
    }

    public String geteName() {
        return eName;
    }

    public void setEName(String eName) {
        this.eName = eName;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Long getMgr() {
        return mgr;
    }

    public void setMgr(Long mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Double getComm() {
        return comm;
    }

    public void setComm(Double comm) {
        this.comm = comm;
    }

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        this.deptno = deptno;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Emp [empNo=");
        builder.append(empNo);
        builder.append(", eName=");
        builder.append(eName);
        builder.append(", job=");
        builder.append(job);
        builder.append(", mgr=");
        builder.append(mgr);
        builder.append(", hiredate=");
        builder.append(hiredate);
        builder.append(", sal=");
        builder.append(sal);
        builder.append(", comm=");
        builder.append(comm);
        builder.append(", deptno=");
        builder.append(deptno);
        builder.append("]");
        return builder.toString();
    }

}

在resource目录新建spring-ioc.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">

    
    <beans>
        <!--
            setter方式注入
            property标签有3个属性:
            name:属性的名称
            value:属性的值
            ref:属性的引用对象(一般引用其他定义好的bean,使用bean标签的id属性的 值)
         -->
        <bean id="emp1" class="com.yyoo.boot.bean.Emp">
            <property name="comm" value="800"></property>
            <property name="deptno" value="10"></property>
            <property name="empNo" value="1220"></property>
            <property name="eName" value="张三"></property>
            <!-- 给hiredate注入null值 -->
            <property name="hiredate"><null/></property>
            <property name="job" value="saler"></property>
            <property name="mgr" value="2281"></property>
            <property name="sal" value="2000"></property>
        </bean>


        <!-- 构造器注入
            constructor-arg标签有5个属性
            name:构造方法参数的名称
            value:构造方法参数的值
            ref:构造方法参数的引用对象(一般引用其他定义好的bean,使用bean标签的id属性的 值)
            index:构造方法参数的索引位置,下标从0开始
            type:构造方法参数的类型
            其中:名称、(类型 + 索引位置)均可以单独确定唯一的参数
            多个构造方法,如:this(int a,int b) 和 this(double c,double d),
            如果只使用index就无法确定到底调用哪个方法,所以再加上类型,才能唯一确定。
        -->
        <bean id="emp2" class="com.yyoo.boot.bean.Emp">
            <constructor-arg index="0" value="2281"></constructor-arg>
            <constructor-arg name="comm" value="300"></constructor-arg>
            <constructor-arg index="1" type="java.lang.String" value="姓名"></constructor-arg>
            <constructor-arg name="job" value="saler"></constructor-arg>
            <constructor-arg name="deptno" value="10"></constructor-arg>
            <constructor-arg name="mgr" value="2000"></constructor-arg>
            <constructor-arg name="sal" value="3000"></constructor-arg>
            <!-- 给hiredate注入null值 -->
            <constructor-arg name="hiredate"><null/></constructor-arg>
        </bean>


        <!--
         spring还支持一个工厂方法方式实例化对象,这里就不过多介绍了
         这里的工厂class就是Emp本身,其实也可以是另外的Factory类的
         -->
        <!-- 工厂模式_静态方法 -->
        <bean id="emp3" class="com.yyoo.boot.bean.Emp" factory-method="newInstance"></bean>

        <!-- 工厂模式_成员方法 -->
        <bean id="emp4" factory-bean="emp3" factory-method="getInstance"></bean>
    </beans>
    
</beans>

这里一口气讲完了Emp对象在spring中的4中实例化方式。

测试主程序

package com.yyoo.boot.ioc;

import com.yyoo.boot.bean.Emp;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Demo1 {

    @Test
    public void test1(){

        ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
        Emp emp1 = context.getBean("emp1", Emp.class);
        System.out.println(emp1);

        Emp emp2 = context.getBean("emp2", Emp.class);
        System.out.println(emp2);

        Emp emp3 = context.getBean("emp3", Emp.class);
        System.out.println(emp3);

        Emp emp4 = context.getBean("emp4", Emp.class);
        System.out.println(emp4);
    }

}

运行结果

Emp [empNo=1220, eName=张三, job=saler, mgr=2281, hiredate=null, sal=2000.0, comm=800.0, deptno=10]
Emp [empNo=2281, eName=姓名, job=saler, mgr=2000, hiredate=null, sal=3000.0, comm=300.0, deptno=10]
Emp [empNo=1000, eName=工厂静态方法注入, job=null, mgr=null, hiredate=null, sal=null, comm=null, deptno=null]
Emp [empNo=1001, eName=工厂实例方法注入, job=null, mgr=null, hiredate=null, sal=null, comm=null, deptno=null]

工程结构图

在这里插入图片描述

我们的Demo使用了JUnit,所以我们将它写在了test包。

Ioc容器功能示意图

在这里插入图片描述
所以的配置元数据都交由Spring 容器管理,程序中通过容器获得的实例都是通过spring 容器 produces(组装、生产)之后成为可直接使用的实例。
上一篇:001-Spring Boot HelloWorld
下一篇:003-Spring Ioc Bean的初始化过程与循环依赖

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值