【Spring学习随笔】2. Spring IoC

时间:2019-11-21
本文章向大家介绍【Spring学习随笔】2. Spring IoC,主要包括【Spring学习随笔】2. Spring IoC使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

2. Spring IoC

2.1 Spring IoC的基本概念

控制反转(Inversion of Control,IoC)是Spring框架的核心,用来消减计算机程序的偶合问题。

依赖注入(Dependency Injection,DI)是IoC的另外一种说法,只是从不同的角度描述相同的概念。

​ 当Spring框架出现后,对象的实例不再由调用者来创建,而是由Spring容器来创建。Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由调用者转移到Spring容器,控制权发生了反转,这就是Spring的控制反转

​ 从Spring容器角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,这就是Spring的依赖注入

​ 综上所述,控制反转是一种通过描述(在Spring中可以是XML或注解)并通过第三方去产生或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入。

2.2 Spring IoC容器

2.2.1 BeanFactory

​ BeanFactory由org.springframework.beans.factory.BeanFactory接口定义,他提供了完整的IoC服务支持,是一个管理Bean的工厂,主要负责初始化各种Bean。BeanFactory接口有多个实现类,其中比较常用的是org.springframework.beans.factory.xml.XmlBeanFactory。

​ 在创建BeanFactory实例时需要提供XML文件的绝对路径。下面是main方法中的一个示例代码:

public static void main(String[] args) {
    //初始化Spring容器,加载配置文件
    BeanFactory beanFac = new XmlBeanFactory(
            new FileSystemResource("D:\eclipse-workspace\ch1\src\
            applicationContext.xml")
    );
    //通过容器获取test实例
    TestDao tt = (TestDao)beanFac.getBean("test");
    tt.sayHello();
}

2.2.2 ApplicationContext

​ ApplicationContext是BeanFactory的子接口,也称为应用上下文,由org.springframework.context.ApplicationContext接口定义。ApplicationContext接口除了包含BeanFactory的所有功能以外,还添加了对国际化、资源访问、事件传播等内容的支持。

​ 创建ApplicationContext接口实例通常有一下3种方法:

  • 通过ClassPathXmlApplicationContext创建

    ClassPathXmlApplicationContext将从类路径目录(src根目录)中寻找指定的XML配置文件。代码如下:

    public static void mian(String[] args) {
        //初始化Spring容器ApplicationContext,加载配置文件
        ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过容器获取test实例
        TestDao tt = new (TestDao)appCon.getBean("test");
        tt.sayHello();
    }
  • 通过FileSystemXmlApplicationContext创建

    FileSystemXmlApplicationContext将从指定文件的绝对路径中寻找XML配置文件,找到并装载完成ApplicationContext的实例化工作。代码如下:

    public static void mian(String[] args) {
        //初始化Spring容器ApplicationContext,加载配置文件
        ApplicationContext appCon = new FileSystemXmlApplicationContext("D:\eclipse-workspace\ch1\src\applicationContext.xml");
        //通过容器获取test实例
        TestDao tt = new (TestDao)appCon.getBean("test");
        tt.sayHello();
    }

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

  • 通过Web服务器实例化ApplicationContext容器

    在Web服务器实例化ApplicationContext容器时,一般使用基于org.framework.web.context.ContextLoaderListener的实现方式(需要将spring-web-x.x.x.RELEASE.jar复制到WEB-INF/lib目录中),此方法只需在web.xml中添加如下代码:

    <context-param>
      <!-- 加载src目录下的applicationContext.xml文件 -->
        <param-name>contextConfigLocation</param-name>
        <param-value>
          classpath:applicationContext.xml
        </param-value>
    </context-param>
    <!-- 指定以ContextLoaderListener方式启动Spring容器 -->
    <listener>
      <listener-class>
          org.framework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

2.3 依赖注入的类型

​ 在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件中。Spring框架的依赖注入通常有两种实现方式,一种是使用构造方法注入,另一种是使用属性的setter方法注入。

2.3.1 使用构造方法注入

​ Spring框架可以采用Java的反射机制,通过构造方法完成依赖注入。

实例讲解:

  • 创建dao包

    创建dao包在service中使用构造方法依赖注入TestDIDao接口对象。

    TestDIDao接口代码如下:

    package dao;
    public interface TestDIDao {
        public void sayHello();
    }

    TestDIDaoImpl实现类代码如下:

    package dao;
    public class TestDIDaoImpl implements TestDIDao {
        @Override
        public void sayHello() {
            system.out.println("TestDIDao say: Hello, Study hard!");
        }
    }
  • 创建service包

    在TestDIServiceImpl中使用构造方法依赖注入TestDIDao接口对象。

    TestDIService接口代码如下:

    package service;
    public interface TestDIService {
        public void sayHello();
    }

    TestDIServiceImpl实现类代码如下:

    package service;
    import dao.TestDIDao;
    public class TestDIServiceImlp implements TestDIService {
        private TestDIDao testDIDao;
        //构造方法,用于实现依赖注入接口对象testDIDao
        public TestDIServiceImpl(TestDIDao testDIDao) {
            super();
            this.testDIDao = testDIDao;
        }
    
        @Override
        public void sayHello() {
            //调用testDIDao中的sayHello方法
            testDIDao.sayHello();
            System.out.prinln("TestDIService构造方法注入say: Hello, Study hard!");
        }
    }
  • 编写配置文件

    在src根目录下根目录下创建Spring配置文件applicationContext.xml。在配置文件中首先将dao.TestDIDaoImpl类托管给Spring,让Spring创建其对象,然后将service.TestDIServiceImpl类托管给Spring,让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执行过程
          创建service实例:BookService bookService = new BookServiceImpl() IoC  <bean>
          创建dao实例:BookDao bookDao = new BookDaoImpl()         IoC
          将dao设置给service:bookService.setBookDao(bookDao);     DI   <property>
    
          <property> 用于进行属性注入
              name: bean的属性名,通过setter方法获得
                  setBookDao ##> BookDao  ##> bookDao
              ref :另一个bean的id值的引用
       -->
    
      <!-- 将指定类TestDIDaoImpl配置给Spring,让Spring创建其实例 -->
        <bean id="myTestDIDao" class="dao.TestDIDaoImpl" />
        <!-- 使用构造方法注入 -->
        <bean id="testDIService" class="service.TestDIServiceImpl">
          <!-- 将myTestDIDao注入到TestDIServiceImpl类的属性testDIDao上 -->
            <constructor-arg index="0" ref="myTestDIDao" />
        </bean>
    
    
    </beans>
    
  • 创建test包

    创建测试类TestDI,代码如下:

    package test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import service.TestDIService;
    public classs TestDI {
        public static void main(String[] args) {
            //初始化Spring容器ApplicationContext,加载配置文件
          ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
          //通过容器获取testDIService实例,测试构造方法注入
          TestDIService ts = (TestDIService)appCon.getBean("testDIService");
          ts.sayHello();
        }  
    }

2.3.2 使用属性的setter方法注入

​ 使用setter方法注入是Spring框架中最主流的注入方式,它利用Java Bean规范所定义的setter方法来完成注入,灵活且可读性高。对于setter方法注入,Spring框架也是使用Java的反射机制实现的。

实例讲解:

  • 创建接口实现类TestDIServiceImpl

    在service包中创建接口实现类TestDIServiceImpl1,在TestDIServiceImpl1中使用属性的setter方法依赖注入TestDIDao接口对象,代码如下:

    package service;
    import dao.TestDIDao;
    public class TestDIServiceImpl implements TestDIService {
        private TestDIDao testDIDao;
        //添加testDIDao属性的setter方法,用于实现依赖注入
        public void set TestDIDao(TestDIDao testDIDao) {
            this.testDIDao = testDIDao;
        }
        @Override
        public void sayHello() {
           //调用testDIDao中的sayHello方法
            testDIDao.sayHello();
            System.out.println("TestDIService setter方法注入 say: Hello, Study hard!");
        }
    }
  • 将TestDIServiceImpl1类托管给Spring

    让Spring创建其对象,同时调用TestDISeriveImpl1类的setter方法完成依赖注入。代码如下:

    <!-- 使用setter方法注入 -->
    <bean id="testDIService1" class="service.TestDIServiceImpl1">
        <!-- 调用TestDIServiceImpl1类的setter方法,将myTestDIDao注入到TestDIServiceImpl1类的属性testDIDao上 -->
        <property name="testDIDao" ref="myTestDIDao" />
    </bean>
    
  • 在test中测试setter方法注入

    //通过容器获取testDIService实例,测试setter方法注入
    TestDIService ts1=(TestDIService)appCon.getBean("testDIService1");
    ts1.sayHello();
    

原文地址:https://www.cnblogs.com/yihangjou/p/11906865.html