主流框架二:Spring(2)Spring的IOC、依赖注入

一、IOC的概念和Spring中基于XML的IOC

(1)IOC概念

IOC:控制反转(把创建对象的权利交给框架)
在这里插入图片描述
原来:
我们在获取对象时,都是采用 new 的方式。是主动的。
现在:
我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。
这种被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一在这里插入图片描述

明确ioc 的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。

(2)使用Spring的IOC来解决程序的耦合

使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体类。

一、业务层的接口和实现类

/**
* 账户的业务层接口
*/
public interface IAccountService {

	/**
	* 保存账户(此处只是模拟,并不是真的要保存)
	*/
	void saveAccount();
}

/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements IAccountService {

	//业务service层调用dao的方法,必须先有dao对象,此处有依赖关系
	private IAccountDao accountDao = new AccountDaoImpl();// 此处的依赖关系有待解决
	@Override
	public void saveAccount() {
		accountDao.saveAccount();
	}
}

二、持久层接口和实现类

/**
* 账户的持久层接口
*/
public interface IAccountDao {

	/**
	* 保存账户
	*/
	void saveAccount();
	
}

/**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements IAccountDao {

	@Override
	public void saveAccount() {
		System.out.println("保存了账户");
	}
}

1.基于xml开发的配置

(1)导包后在resources配置目录下创建bean.xml配置文件

<!--    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">
</beans>

(2)让spring管理资源,在配置文件中配置 service 和 dao

<!--    把对象的创建交给spring来管理-->
<!-- bean 标签:用于配置让 spring 创建对象,并且存入 ioc 容器之中
	id 属性:对象的唯一标识。
	class 属性:指定要创建对象的全限定类名
-->
    <bean id="accountService" class="com.swpuembedded.service.impl.AccountServiceImpl"></bean>

    <bean id="accountDao" class="com.swpuembedded.dao.impl.AccountDaoImpl"></bean>

(3)模拟一个表现层(web)来测试配置是否成功

/**
* 模拟一个表现层
*/
public class Client {
	/**
	* 使用 main 方法获取容器测试执行
	*/
	public static void main(String[] args) {
		//1.使用 ApplicationContext 接口,就是在获取 spring 容器
		//通过classpath来获取配置文件中bean内容的容器
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		
		//2.根据 bean 的 id 从spring容器(applicationContext)获取对象
		IAccountService aService = (IAccountService) ac.getBean("accountService");
		IAccountDao aDao = (IAccountDao) ac.getBean("accountDao");
		
		System.out.println(aService);
		System.out.println(aDao);
	}
}

2.ApplicationContext

ApplicationContext实际是就是spring中的一个工厂,通过工厂来获取bean对象。

(1)Spring的工厂类结构图
在这里插入图片描述
在这里插入图片描述

BeanFactory 才是 Spring 容器中的顶层接口。  ApplicationContext 是它的子接口。
核心容器的两个接口引发出的问题
* ApplicationContext:      单例对象       (智能) 更多采取此接口
*      它在构建核心容器时,创建对象采取的思想策略是采用立即加载的方式,也就是说只要一读取完配置文件就创建配置文件中配置的对象。
* BeanFactory:             多例对象
*      它在构建核心容器时,创建对象采取的思想策略是采用延迟加载的方式,也就是说什么时候根据id获取对象了,什么时候才真正的创建对象。
     

(2)ApplicationContext的三个常用的实现类
获取Spring的IOC核心容器,并根据ID获取对象

 * (1)ClassPathXmlApplicationContext
 *      可以加载类路径下的配置文件(配置文件在类的路径下,不在无法加载)
 * (2)FileSystemXmlApplicationContext
 *      可以加载磁盘任意路径,毕竟File,(必须有访问的权限)
 * (3)AnnotationConfigApplicationContext
 *      可以用于读取注解来创建容器,之后用的现在是xml配置

二、IOC中 bean标签 和 管理对象细节

(1)bean标签

在我们的bean.xml配置文件中,我们需要关注一些细节。

bean标签:用于配置对象让 spring 来创建的。默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。

id:给对象在容器中提供一个唯一标识。用于获取对象。
class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。
	* singleton :默认值,单例的.
	* prototype :多例的.
<!--    把对象的创建交给spring来管理-->
    <bean id="accountService" class="com.swpuembedded.service.impl.AccountServiceImpl"></bean>

    <bean id="accountDao" class="com.swpuembedded.dao.impl.AccountDaoImpl"></bean>

(2)Spring对bean的管理细节

1.创建bean的三种方式

第一种方式:使用默认构造函数创建
在spring的配置文件中使用bean标签,配以id和class且没有其他属性和标签时,采用的就是默认构造函数bean对象,此时如果类中没有默认构造函数,则实例化对象(AccountServiceImpl)无法创建

<bean id="accountService" class="com.swpuembedded.service.impl.AccountServiceImpl"></bean>
/**
 * @author Mango
 * 账户的业务层接口的实现类
 */
public class AccountServiceImpl implements IAccountService {

    public AccountServiceImpl() {
        System.out.println("AccountServiceImpl对象创建了");
    }


    public void saveAccount() {
        System.out.println("service中的saveAccount方法执行了");
    }
}

在这里插入图片描述
第二种方式:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象并存入spring容器)

				该类存在jar包,InstanceFactory只是模拟而已
<bean id="instanceFactory" class="com.swpuembedded.factory.InstanceFactory"></bean>

<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
/**
 1. @author Mango
 2. 模拟一个工厂类,该类存在jar包,无法通过修改源码方式来提供默认构造函数
 */
public class InstanceFactory {

    public IAccountService getAccountService() {
        return new AccountServiceImpl();
    }
}

第三种方式:使用静态工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

<bean id="accountService" class="com.swpuembedded.factory.StaticFactory" factory-method="getAccountService"></bean>
与第二种方法的区别只是方法成为了静态方法,便可在class后加factory-method
/**
 3. @author Mango
 4. 使用静态工厂中的静态方法创建对象
 */
public class StaticFactory {

    public static IAccountService getAccountService() {
        return new AccountServiceImpl();
    }
}

2.bean对象的作用范围

bean标签中的scope属性
(1)作用:用于指定bean的作用范围

一个应用只有一个对象的实例。或者是,每次访问对象时,都会重新创建对象实例。

(2)取值:常用的就是单例和多例的
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session在这里插入图片描述

3.bean对象的生命周期

(1)单例对象
创建:当容器创建时,对象变创建
存在:只要容器存在,对象一直存在
销毁:只要容器销毁,便销毁了
注:单例对象与容器的生命周期相同

(2)多例对象
创建:当我们使用对象时,spring框架才为我们创建
存在:对象只要是在使用过程中就一直存在
销毁:当对象长时间的不使用时,且没有别的对象引用时,由Java的垃圾回收器回收

三、依赖注入(Dependency Injection)

概念:在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,就成为依赖注入

(1)注入数据类型

依赖注入(使用bean标签):能注入的数据,有三类
(1)基本类型和String
(2)其他的bean类型(在配置文件中或者注解配置过得bean

<bean id="accountService2" class="com.swpuembedded.service.impl.AccountServiceImpl2">
    <property name="name" value="泰斯特"></property>
    <property name="age"  value="18"></property>
    <property name="birthday" ref="now"></property>
</bean>

<!--    通过字节码文件新建一个birthday对象存入容器,用id获取-->
    <bean id="now" class="java.util.Date"></bean>

(3)复杂类型/集合类型

(2)注入方式

注入的方式,有三种:

第一种:使用构造函数来提供

顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。

使用的标签是:constructor-arg
标签出现的位置是:bean标签的内部
标签中的属性
type:用于指定要注入的数据的数据类型,数据类型也是构造函数中的某个或者某些参数的类型
index:用于指定要注入的数据构造函数中指定索引位置的参数赋值,索引的位置为0开始
name:用于指定给构造函数中指定名称的参数赋值 (常用的)

//用于指定给构造函数中哪个参数赋值
value:用于给基本类型(string)的数据
ref:用于指定其他的bean类型,它指的就是在spring的IOC核心容器中出现过的bean对象

优势:在获取bean对象时,注入数据时必须的操作,否则对象无法创建成功
弊端:改变了bean对象的实例化方式,使我们在创建对象时如果用不到也必须提供。
    <bean id="accountService" class="com.swpuembedded.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="test"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
		<!--ref引用关联的bean对象-->
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>

第二种:使用set方法提供

涉及的标签:property 出现的位置:bean标签的内部

标签的属性:
name:name:用于指定注入时所调用的set方法名称,不管类中的属性名称
value:用于给基本类型(string)的数据
ref:用于指定其他的bean类型,它指的就是在spring的IOC核心容器中出现过的bean对象

优势:创建对象时没有明确的限制。可以直接使用默认构造函数
弊端:如果某个成员必须有值,则获取对象时有可能set方法没有执行
<bean id="accountService2" class="com.swpuembedded.service.impl.AccountServiceImpl2">
    <property name="name" value="泰斯特"></property>
    <property name="age"  value="18"></property>
    <property name="birthday" ref="now"></property>
</bean>

第三种:使用注解来提供(之后具体写)

(3)注入集合属性—多个值

顾名思义就是给类中的集合成员传值。

它用的也是set方法注入的方式,只不过变量的数据类型都是集合。我们这里介绍注入数组List,Set,Map,Properties。

在需要引入依赖的类中:

/***/
public class AccountServiceImpl implements IAccountService {
	private String[] myStrs;
	private List<String> myList;
	private Set<String> mySet;
	private Map<String,String> myMap;
	private Properties myProps;
	
	public void setMyStrs(String[] myStrs) {
		this.myStrs = myStrs;
	}
	public void setMyList(List<String> myList) {
		this.myList = myList;
	}
	public void setMySet(Set<String> mySet) {
		this.mySet = mySet;
	}
	public void setMyMap(Map<String, String> myMap) {
		this.myMap = myMap;
	}
	public void setMyProps(Properties myProps) {
		this.myProps = myProps;
	}
	
	@Override
	public void saveAccount() {
		System.out.println(Arrays.toString(myStrs));
		System.out.println(myList);
		System.out.println(mySet);
		System.out.println(myMap);
		System.out.println(myProps);
	}
}
<!--    复杂类型的注入/集合类型注入
    用于给list结构集合注入的标签-
        list array set
    用于Map结构集合注入的标签
        map props
    结构相同,标签可以替换
        
-->
<bean id="accountService3" class="com.swpuembedded.service.impl.AccountServiceImp3">
<!--    myStrs-->
    <property name="myStrs">
        <array>
            <value>AAA</value>
            <value>BBB</value>
        </array>
    </property>

    <property name="myList">
        <list>
            <value>AAA</value>
            <value>BBB</value>
        </list>
    </property>

    <property name="mySet">
        <set>
            <value>AAA</value>
            <value>BBB</value>
        </set>
    </property>

    <property name="myMap">
        <map>
            <entry key="testA" value="AAA"></entry>
            <entry key="testB" value="BBB"></entry>
        </map>
    </property>

    <property name="myProperties">
        <props>
            <prop key="testC">CCC</prop>
            <prop key="testD">DDD</prop>
        </props>
    </property>

</bean>
发布了47 篇原创文章 · 获赞 18 · 访问量 4874

猜你喜欢

转载自blog.csdn.net/qq_43605085/article/details/98313908