一、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>