【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-workspacech1src
    		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-workspacech1srcapplicationContext.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.println("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 setTestDIDao(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