spring学习笔记(2):IOC和DI

mac2022-06-30  28

文章目录

一、IOC的概念和作用1基本概念 二、使用spring框架来实现前文的解耦案例1.项目环境搭建2.ApplicationContext的3个常用实现类3.核心容器的两个接口引发的问题3.1`ApplicationContext`3.2`BeanFactory`3.3使用选择 三、spring对bean的管理细节1.创建bean的三种方式1.1方式一:使用默认构造函数1.2方式二:使用实例工厂的方法创建对象1.3方式三:使用静态工厂的静态方法来创建对象 2.bean的作用范围2.1默认作用范围( singleton:单例的)2.2设置多例的作用范围( prototype)2.3小结2.4global-session简单了解 3.bean对象的生命周期3.1单例对象的生命周期3.2多例对象的生命周期 四、spring的依赖注入1.基本概念2注入数据类型和方式2.1三类数据2.2三种注入方式 3第一种注入方式:使用构造函数提供3.1bean类提供带参的构造函数3.2配置方法3.2.1配置实例 3.3运行效果3.4优势和弊端 4第二种注入方式:使用set方法提供(更常用)4.1bean类提供属性的set方法4.2配置方法4.2.1配置实例 4.3运行效果4.4优势和弊端 5.复杂数据类型(集合类型)的注入案例5.1含有复杂数据类型的bean类5.2配置方法5.2.1标签小结 5.3运行效果

一、IOC的概念和作用

1基本概念

这里我们先简单总结下前文中创建对象的两种方式

前文中两种不同的方式来创建对象就是一个典型的对比 - 前一种获取对象的方式是主动的,直接new,将应用和资源直接绑定在一起 - 后一种方式,把创建对象交给工厂,我们只需要和工厂打交道即可 - 由工厂来控制资源和提供资源,减少程序间的耦合性

二、使用spring框架来实现前文的解耦案例

1.项目环境搭建

创建maven项目复制上文的主要代码设置pom.xml文件,导入spring的jar包坐标 <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> 导入后,可以发现相关jar包的信息 新建资源文件bean.xml导入约束 接下来把对象的创建交给spring来管理,在配置文件中进行配置 <!-- id:唯一标志 class:bean类的全限定类名 --> <bean id="accountService" class="com.xpt.service.impl.AccountServiceImpl"></bean> <bean id="accountDao" class="com.xpt.dao.impl.AccountDaoImpl"></bean> 创建对象,分为如下两步 获取core对象根据配置文件中的id获取对象 public class Client { public static void main(String[] args) { //1.获取核心容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取对象 IAccountService as = (IAccountService) ac.getBean("accountService"); IAccountDao dao = (IAccountDao) ac.getBean("accountDao"); System.out.println(as); System.out.println(dao); } }

- 可以看到上述的过程代码非常的少,从配置文件解析到对象创建全都由spring做了

2.ApplicationContext的3个常用实现类

ClassPathXmlApplicationContext:加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了。(相较于下一种更推荐使用)FileSystemXmlApplicationContext:可以加载磁盘任意路径下的配置文件,但必须有访问权限AnnotationConfigApplicationContext:它是用于读取注解创建容器的。

3.核心容器的两个接口引发的问题

3.1ApplicationContext

它在创建核心容器时,对象创建的策略是采用立即加载的方式,也就是说,只要一读取完配置文件就能马上创建配置文件种配置好的对象。

验证:在bean类中定义一个空参的构造函数 public class AccountServiceImpl implements IAccountService { IAccountDao accountDao = new AccountDaoImpl(); public AccountServiceImpl(){ System.out.println("对象已经被创建了"); } public void saveAccount() { accountDao.saveAccount(); } } Client类中注释掉后面的对象获取 public class Client { public static void main(String[] args) { //1.获取核心容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); // //2.根据id获取对象 // IAccountService as = (IAccountService) ac.getBean("accountService"); // IAccountDao dao = (IAccountDao) ac.getBean("accountDao"); // System.out.println(as); // System.out.println(dao); } } 运行效果:

3.2BeanFactory

它在构建核心容器的时候,创建对象的策略是采用延迟加载的方式,也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。

演示:修改代码 Resource resource = new ClassPathResource("bean.xml"); BeanFactory factory = new XmlBeanFactory(resource); IAccountService as = (IAccountService) factory.getBean("accountService"); System.out.println(as); 断点调试 - 继续执行

3.3使用选择

上面演示了两种容器接口创建对象的不同时机,那在实际开发中如何选择呢?单例对象的情况下,对象只被创建一次,然后多次使用,这种时候肯定希望立即加载,所以ApplicationContext更适用于单例对象,那么显然BeanFactory更适用于多例对象使用

三、spring对bean的管理细节

1.创建bean的三种方式

1.1方式一:使用默认构造函数

在spring的配置文件中使用bean标签,配以id和class属性,且没有其他的属性和标签时。采用的就算默认构造函数创建bean对象,如果此时类中没有默认构造函数,则对象无法创建

演示效果配置文件 <bean id="accountService" class="com.xpt.service.impl.AccountServiceImpl"></bean> 设置bean类无默认构造函数 public class AccountServiceImpl implements IAccountService { //增加参数 使当前类没有默认的构造函数 public AccountServiceImpl(String name){ System.out.println("对象已经被创建了"); } public void saveAccount() { System.out.println("service中的saveAccount方法执行了"); } } 测试类 public class Client { public static void main(String[] args) { //1.获取核心容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取对象 IAccountService as = (IAccountService) ac.getBean("accountService"); System.out.println(as); } } 运行结果报错

1.2方式二:使用实例工厂的方法创建对象

使用普通工厂中的方法创建对象 或者使用某个类中的方法创建对象,并存入spring容器

演示配置 <bean id="instanceFactory" class="com.xpt.factory.InstanceFactory"></bean> <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean> 模拟实例工厂类 public class InstanceFactory { public IAccountService getAccountService(){ return new AccountServiceImpl(); } } 其余部分代码不变,之间运行测试类,结果成功创建对象

1.3方式三:使用静态工厂的静态方法来创建对象

使用静态工厂的静态方法来创建对象 或者使用某个类的静态方法创建对象,并存入spring容器

演示配置 <bean id="accountService" class="com.xpt.factory.StaticFactory" factory-method="getAccountService" ></bean> 静态工厂和静态方法 public class StaticFactory { public static IAccountService getAccountService(){ return new AccountServiceImpl(); } } 其余代码不变,直接运行测试类,成功创建对象

2.bean的作用范围

2.1默认作用范围( singleton:单例的)

默认作用范围是单例的,即创建的bean都是一个对象

演示

2.2设置多例的作用范围( prototype)

xml配置 - 运行测试

2.3小结

bean标签的scope属性: 作用:用于指定bean的作用范围 取值: 常用的就是单例的和多例的

singleton:单例的(默认值)prototype:多例的request:作用于web应用的请求范围session:作用于web应用的会话范围global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session

2.4global-session简单了解

3.bean对象的生命周期

3.1单例对象的生命周期

出生:当容器创建时对象出生

活着:只要容器还在,对象一直活着

死亡:容器销毁,对象消亡

总结:单例对象的生命周期和容器相同

演示

xml配置

bean类中添加init和destroy方法 public void saveAccount() { System.out.println("service中的saveAccount方法执行了"); } public void init() { System.out.println("对象创建"); } public void destroy() { System.out.println("对象销毁"); } 测试类改造: - 结果:

3.2多例对象的生命周期

出生:当我们使用对象时spring框架为我们创建(延迟加载,spring会智能的判断对象是单例还是多例的,然后智能选择加载方式,这里回想前面核心容器的两个不同的加载方式)活着:对象只要是在使用过程中就一直活着。死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收验证xml配置 - 其余部分不变,测试代码结果

四、spring的依赖注入

1.基本概念

依赖注入:Dependency InjectionIOC的作用: 降低程序间的耦合(依赖关系)依赖关系的管理:以后都交给spring来维护在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明,依赖关系的维护:就称之为依赖注入。

2注入数据类型和方式

2.1三类数据

基本类型和String其他bean类型(在配置文件中或者注解配置过的bean)复杂类型/集合类型

2.2三种注入方式

第一种:使用构造函数提供第二种:使用set方法提供第三种:使用注解提供

3第一种注入方式:使用构造函数提供

下面演示基于这种方式的配置过程

3.1bean类提供带参的构造函数

public class AccountServiceImpl implements IAccountService { //如果是经常变化的数据,并不适用于注入的方式 private String name; private Integer age; private Date birthday; public AccountServiceImpl(String name, Integer age, Date birthday) { this.name = name; this.age = age; this.birthday = birthday; } public void saveAccount() { System.out.println("service中的saveAccount方法执行了:"+name+","+age+","+birthday); } }

注意

现在上述的bean类中没有默认的构造函数,所以在配置的时候肯定无法使用默认的构造函数来创建bean对象 - 所以为了解决上面的问题就需要进行构造函数的依赖注入的配置

3.2配置方法

使用的标签:constructor-arg标签出现的位置:bean标签的内部标签中的属性 type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始name:用于指定给构造函数中指定名称的参数赋值(推荐) 以上三个用于指定给构造函数中哪个参数赋值 value:用于提供基本类型和String类型的数据ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

3.2.1配置实例

3.3运行效果

代码 public class Client { public static void main(String[] args) { //1.获取核心容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根据id获取对象 IAccountService as = (IAccountService) ac.getBean("accountService"); System.out.println(as); as.saveAccount(); } } 结果 - 顺利执行

3.4优势和弊端

优势: 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

4第二种注入方式:使用set方法提供(更常用)

4.1bean类提供属性的set方法

只提供set方法即可

4.2配置方法

涉及的标签:property出现的位置:bean标签的内部标签的属性 name:用于指定注入变量的名称value:用于提供基本类型和String类型的数据ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

4.2.1配置实例

4.3运行效果

代码同上

4.4优势和弊端

优势:创建对象时没有明确的限制,可以直接使用默认构造函数弊端: 如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

5.复杂数据类型(集合类型)的注入案例

使用set方式注入复杂数据类型

5.1含有复杂数据类型的bean类

public class AccountServiceImpl3 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; } 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); }

5.2配置方法

配置实例 <bean id="accountService03" class="com.xpt.service.impl.AccountServiceImpl3"> <property name="myStrs"> <array> <value>array</value> </array> </property> <property name="myList"> <list> <value>list</value> </list> </property> <property name="mySet"> <set> <value>set</value> </set> </property> <property name="myMap"> <map> <entry key="mapA" value="valueA"></entry> <entry key="mapB" value="valueB"></entry> </map> </property> <property name="myProps"> <props> <prop key="propA">valueA</prop> </props> </property> </bean>

5.2.1标签小结

用于给List结构集合注入的标签: list array set用于个Map结构集合注入的标签: map props结构相同,标签可以互换

5.3运行效果

最新回复(0)