【Spring】IOC和DI
背景
private IAccountDao accountDao=new AccountDaoImpl();
采用new的方式创建对象,找对象是主动的,APP和资源之间存在无法消除的联系,对于资源和应用的独立变得很难。
private IAccountDao account=(IAccountDao)BeanFactory.getBean("account)
APP断开和资源的联系,由工厂来分配资源,由工厂和资源取得联系,再将想要的对象转到app。
但是在spring中,将完全自己创建对象的权利放弃,交给BeanFactory,由BeanFactory和一个固定的名称找到想要的对象,但这个Bean对象是否能用,应用无法得知,因为工厂根据全限定类名来创建类的对象,无法自己独立控制,和new的方式不同,new的方式可以独立控制,这种控制权发生的转移叫做控制反转,从而削减依赖,降低计算机的耦合。
控制反转(Inversion of control):把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语,包括依赖注入(Dependency Injection) 和依赖查找(Dependency Lookup)
使用Spring的IOC解决程序耦合
- 准备Spring的开发包,项目中直接通过Maven引入
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency></dependencies>
spring中工厂的类结构图
2. 表现层
/*** 模拟一个表现层,用于调用业务层*/
public class Client {public static void main(String[] args) {//1. 获取核心容器类ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");//2. 根据id获取Bean对象IAccountService as = (IAccountService)ac.getBean("accountService");//Object类型强转IAccountDao adao=ac.getBean("accountDao",IAccountDao.class);//字节码进行强转System.out.println(as);System.out.println(adao);}
}
- 业务层接口和实现类
/*** 账户业务层的接口*/
public interface IAccountService {/*** 模拟保存账户*/void saveAccount();
}
/*** 账户的业务层实现类*/
public class AccountServiceImpl implements IAccountService {private IAccountDao accountDao=new AccountDaoImpl();@Overridepublic void saveAccount() {accountDao.saveAccount();}
}
- 持久层接口和实现类
/*** 账户的持久层接口*/
public interface IAccountDao {/*** 模拟保存账户的操作*/void saveAccount();
}
/*** 账户的持久层实现类*/
public class AccountDaoImpl implements IAccountDao {@Overridepublic void saveAccount() {System.out.println("保存了");}
}
- 配置XML中的bean信息
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--把对象的创建交给spring来管理--><bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl"></bean><bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
</beans>
- 运行结果
com.itheima.Service.impl.AccountServiceImpl@1a052a00
com.itheima.dao.impl.AccountDaoImpl@4d826d77Process finished with exit code 0
ApplicationContext的三个实现类
- ApplicationContext的三个常用实现类:
- ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了
- FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
- AnnotationConfigApplicationContext:它是用于读取注解创建容器的。
//采用ClassPathXmlApplicationContext方式
ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");//采用FileSystemXmlApplicationContext方式
ApplicationContext ac=new FileSystemXmlApplicationContext("C:\\Users\\Z\\Desktop\\day01_eesy_03spring\\src\\main\\resources");
- 核心容器的两个接口引发出的问题:
- ApplicationContext:
- 它在构建核心容器时,创建对象采用的策略是采用立即加载的方式。也就是说,只要已读取完配置马上创建配置文件中配置的对象
- 适用:单例对象
- BeanFactory:
- 它在构建核心容器时,创建对象采用的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象,什么时候才真正的创建对象
- 适用:多例对象
ApplicationContext demo
修改业务层实现类的构造方法
/*** 账户的业务层实现类*/
public class AccountServiceImpl implements IAccountService {private IAccountDao accountDao=new AccountDaoImpl();public AccountServiceImpl(){System.out.println("对象创建了");}@Overridepublic void saveAccount() {accountDao.saveAccount();}
}
运行结果:
BeanFactory Demo
表现层
public class Client {public static void main(String[] args) {Resource resource=new ClassPathResource("bean.xml");BeanFactory factory=new XmlBeanFactory(resource);IAccountService as=(IAccountService)factory.getBean("accountService");System.out.println(as);}
}
运行结果
对比ApplicationContext和BeanFactory
ApplicationContext:较为智能,能根据单例/多例判断采用立即/延迟加载策略
BeanFactory:作为顶层接口,封装等不太完善
Spring中对Bean的管理细节
- Bean的三种创建方式
1.1 使用默认构造函数创建:在Spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。采用的就是默认构造函数来创建bean对象,此时如果类中没有默认的构造函数,则对象无法创建。
bean.xml
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl"></bean>
</beans>
实现层
/*** 模拟一个表现层,用于调用业务层*/
public class Client {/*** @param args*/public static void main(String[] args) {//1. 获取核心容器类ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");//2. 根据id获取Bean对象IAccountService as = (IAccountService)ac.getBean("accountService");System.out.println(as);as.saveAccount();}
}
业务接口层
/*** 账户业务层的接口*/
public interface IAccountService {/*** 模拟保存账户*/void saveAccount();
}
业务实现层
/*** 账户的业务层实现类*/
public class AccountServiceImpl implements IAccountService {public AccountServiceImpl(String name){System.out.println("对象创建了");}@Overridepublic void saveAccount() {System.out.println("service中的代码执行了。。。");}
}
运行结果:
1.2 使用普通工厂的方法创建对象(使用某个类中的方法创建对象,并存入Spring容器)
InstanceFactory
import com.itheima.Service.impl.AccountServiceImpl;
/*** 模拟一个工厂类(该类可能存在于jar包中,无法修改源码的方式来提供默认构造函数)*/
public class InstanceFactory {public AccountServiceImpl getAccountService(){return new AccountServiceImpl();}
}
bean.xml
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean><bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean></beans>
运行结果:
对象创建了
com.itheima.Service.impl.AccountServiceImpl@400cff1a
service中的代码执行了。。。
1.3 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
staticFactory
package com.itheima.factory;import com.itheima.Service.impl.AccountServiceImpl;/*** 模拟一个工厂类(该类可能存在于jar包中,无法修改源码的方式来提供默认构造函数)*/
public class StaticFactory {public static AccountServiceImpl getAccountService(){return new AccountServiceImpl();}
}
bean.xml
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService"></bean></beans>
- Bean的作用范围调整
bean标签的scope属性作用:用于指定bean的作用范围取值:常用的就是单例的和多例的singleton:单例的(默认)prototype:多例的request:作用于web应用的请求范围session:作用于web应用的会话范围global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境的时候,它就是session
- bean的生命周期
单例对象:出生:当容器创建对象出生活着:只要容器还在,对象一直活着死亡:容器销毁,对象消亡总结:单例对象的生命周期和容器相同
多例对象:出生:当我们使用对象时spring框架为我们创建活着:对象只要是在使用过程中就一直活着死亡:当对象长时间不使用,且没有别的对象引用时,由Java的垃圾回收器回收总结:
单例demo
bean.xml
<bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl"scope="singleton" init-method="init" destroy-method="destroy"></bean>
业务实现层
public class AccountServiceImpl implements IAccountService {public AccountServiceImpl(){System.out.println("对象创建了");}@Overridepublic void saveAccount() {System.out.println("service中的代码执行了。。。");}public void init() {System.out.println("init的代码执行了。。。");}public void destroy() {System.out.println("destroy的代码执行了。。。");}
}
表现层
/*** 模拟一个表现层,用于调用业务层*/
public class Client {/*** @param args*/public static void main(String[] args) {//1. 获取核心容器类//ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");//2. 根据id获取Bean对象IAccountService as = (IAccountService)ac.getBean("accountService");as.saveAccount();ac.close();}
}
运行结果
对象创建了
init的代码执行了。。。
service中的代码执行了。。。
十月 28, 2020 10:15:29 上午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3c09711b: startup date [Wed Oct 28 10:15:25 CST 2020]; root of context hierarchy
destroy的代码执行了。。。
Disconnected from the target VM, address: '127.0.0.1:2861', transport: 'socket'
多例demo
bean.xml
<bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl"scope="prototype" init-method="init" destroy-method="destroy"></bean>
运行结果:
对象创建了
init的代码执行了。。。
service中的代码执行了。。。
十月 28, 2020 10:14:02 上午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3c09711b: startup date [Wed Oct 28 10:13:57 CST 2020]; root of context hierarchy
Disconnected from the target VM, address: '127.0.0.1:2853', transport: 'socket'Process finished with exit code 0
Spring中的依赖注入DI(Dependency Injection)
ioc的出现是为了降低程序间的耦合(依赖管理),依赖关系的管理都交给spring来维护,当当前类需要其他类的对象,由spring为提供,只需要在配置文件中说明,依赖关系的维护就是依赖注入。
注入的数据有三类:基本类型和String其他类型(在配置文件中或者注解中配置过的bean)复杂类型/集合类型
注入的方式有三种:1.使用构造函数注入2.使用set方法注入3.使用注解
- 构造器注入
使用标签:constructora-arg
标签出现的位置:bean标签内部
标签中的属性
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始的
name:用于指定给构造函数中指定名称的参数赋值(常用)
=以上三个用于指定给构造函数中哪个参数赋值=
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它值的就是在spring的ioc核心容器中出现过的bean对象
优点:
在获取bean的时候,注入数据时必须的操作,否则对象无法创建成功
缺点:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
业务层实现类
/*** 账户的业务层实现类*/
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;}@Overridepublic void saveAccount() {System.out.println("service中的代码执行了。。。"+name+"--"+age+"--"+birthday);}
}
bean
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl"><constructor-arg name="name" value="赵芬"></constructor-arg><constructor-arg name="age" value="18"></constructor-arg><constructor-arg name="birthday" ref="now"></constructor-arg></bean><!--配置一个日期对象--><bean id="now" class="java.util.Date"></bean></beans>
表现层
public class Client {/*** @param args*/public static void main(String[] args) {//1. 获取核心容器类ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");//2. 根据id获取Bean对象IAccountService as = (IAccountService)ac.getBean("accountService");as.saveAccount();}
}
运行结果:
service中的代码执行了。。。赵芬--18--Wed Oct 28 10:59:43 CST 2020
Disconnected from the target VM, address: '127.0.0.1:3085', transport: 'socket'
- Set方法注入(更常用的方式)
涉及的标签:property
出现的位置:bean标签内部
标签的属性:name:用于指定注入时所调用的set方法名称value:用于提供基本类型和String类型的数据ref:用于指定其他的bean类型数据。它指定就是在Spring的IOC核心容器中出现过的bean对象
优势:创建对象时没有明确的限制,可以直接使用默认构造函数
劣势:如果有某个成员必须有值,则获取对象时有可能set方法没有执行
bean.xml```bash
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl2"><property name="name" value="赵芬"></property><property name="age" value="18"></property><property name="birthday" ref="now"></property></bean><!--配置一个日期对象--><bean id="now" class="java.util.Date"></bean></beans>
表现层
public class Client {/*** @param args*/public static void main(String[] args) {//1. 获取核心容器类ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");//2. 根据id获取Bean对象IAccountService as = (IAccountService)ac.getBean("accountService");as.saveAccount();}
}
业务实现层
/*** 账户的业务层实现类*/
public class AccountServiceImpl2 implements IAccountService {public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}public void setBirthday(Date birthday) {this.birthday = birthday;}//对于经常变化的数据,不建议使用注入方式private String name;private Integer age;private Date birthday;@Overridepublic void saveAccount() {System.out.println("service中的代码执行了。。。"+name+"--"+age+"--"+birthday);}
}
结果
service中的代码执行了。。。赵芬--18--Wed Oct 28 11:16:21 CST 2020
- 注入集合
复杂类型的注入/集合类型的注入用于给List结构集合注入的标签:list,array,set用于给Map结构集合注入的标签:map props结构相同,标签可以互换
bean.xml
<bean id="accountService" class="com.itheima.Service.impl.AccountServiceImpl3"><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</value></entry></map></property><property name="myProps"><props><prop key="testc">ccc</prop></props></property></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;}@Overridepublic void saveAccount() {System.out.println(Arrays.toString(myStrs));System.out.println(myList);System.out.println(mySet);System.out.println(myMap);System.out.println(myProps);}
}
【Spring】IOC和DI相关推荐
- spring IOC和DI
spring IOC and DI 1.IOC和DI的区别: IOC:对象的管理权由spring容器掌握(管理权限包括:对象的创建时间点.创建方式以及对象属性的管理): DI:spring操作对象属性 ...
- 手写实现Spring(IOC、DI),SpringMVC基础功能
手写实现Spring(IOC.DI),SpringMVC功能 spring和springMVC的用法相信大家都不陌生,我简单讲下我实现的思路 spring阶段 事项 配置 配置web.xml: ini ...
- 浅谈Spring IOC和DI及Spring工厂类
浅谈Spring IOC和DI及Spring的工厂类 文章目录 浅谈Spring IOC和DI及Spring的工厂类 一. IOC 1.什么是IOC 2.为什么使用IOC 传统开发模式的弊端 3. 使 ...
- Spring IOC与DI、反射的理解 含小案例说明
阅览了很多篇博文,对于Spring IOC和DI看到很多人介绍的感觉都很含糊,读完之后还是觉得混淆的不行,也有的人认为DI是IOC的另一种说法-emm,可能个人理解不同吧,我的观点并不然.但这种东西, ...
- spring IOC和DI 理解
IOC(控制反转)和DI(依赖注入)是spring中的重要组成部分,下面是个人的一些理解,不代表官方. 1.IOC是什么? IOC:全名是Inversion of Controller 中文解释是控制 ...
- Spring IOC和DI
Spring IOC和DI 框架: 将一些公用的模块进行集成,通过框架的形式进行管理(事务控制,权限控制(Shiro),日志收集log) Spring框架 SSH: Struts2(配置重型)+ ...
- Spring:IoC和DI完成打印机打印详细说明过程及代码
Spring:IoC和DI完成打印机 课后作业 使用Spring的IoC.DI 装配一台打印机 纸张接口 实现 有: A4 A5 墨盒接口 实现 有:黑白 彩色 注解方式和非注解方式都要 说明:1.首 ...
- 关于RuoYi中Spring IOC、DI以及MVC不同注解的使用
1.什么是Spring IOC.DI? IOC(inverse of control)即"控制反转",DI(Dependence Injection)即"依赖注入&quo ...
- 彻底理解Spring IOC和DI
目录 前言 1. 分享Iteye的开涛对Ioc的精彩讲解 1.1 IoC是什么 1.2 IoC能做什么 1.3 IoC和DI 2. 分享Bromon的blog上对IoC与DI浅显易懂的讲解 2.1 I ...
- Spring IoC、DI、Bean和自动装配的理解
文章目录 IoC创建对象 DI依赖注入 Bean的理解 自动装配 IoC创建对象 我们都知道IoC是控制反转的,也就是我们只需要把类注册到Spring容器中,他可以帮助我们创建对象,该创建的思想也就是 ...
最新文章
- 修改审查元素怎么保存_手机qq性别怎么改成空白
- MATLAB符号运算(3)
- layui 鼠标移入变为小手_如何在 LayUI 数据表格的列元素上,鼠标悬浮,显示所有文字内容(修改源码)...
- 缓存/内存型数据库 Redis
- python的sorted函数和operator.itemgetter函数
- 基于Springboot的旅游管理系统
- Robo3T连接远程mongodb
- 顶级区块链开发人员工具:涉及框架、IDE、安全工具、测试网络、区块链预言机和节点服务
- 网页在线PS网站源码PHP 浏览器在线P图
- 百度地图android兼容,支持离线地图 百度地图Android版上线
- 大数据可视化常用的方式有哪些
- SEO优化核心盘点,解谜、扫雷、权重提升统统在这
- 微软放弃收购雅虎猜想:杨致远代价不菲的胜利
- 我转行程序员的那一年(六)
- Poi HSSFCellStyle.ALIGN_CENTER VERTICAL_CENTER 等爆红的解决办法
- 聊聊手机之--小米6
- 拼多多怎么做?无货源新手怎么轻松上手?(小珏)
- java learn 日期
- Json 处理 - golang
- Unity使用全局钩子
热门文章
- ios内购php验证码,PHP (Laravel) 实现 iOS 内购服务端验证
- Microsoft SQL Server Management Studio 附加数据库时出错。有关详细信息,请单击……
- 11.4.9 MONTH(date)函数
- 小米MACE开源框架搭建
- 适用于mac的Tor浏览器?
- 计算机可移动磁盘自动启动,(在线求助)为什么一开机所有硬盘就自动设为默认共享?...
- 程序状态寄存器PSR
- 强烈质疑“步行1公里就能坐上地铁”
- 【Leetcode -1721.交换链表中的节点 -2058.找出临界点之间的最小和最大距离】
- 第三章:zigbee学习笔记之物理层和mac层帧格式分析