背景

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解决程序耦合

  1. 准备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);}
}
  1. 业务层接口和实现类
/*** 账户业务层的接口*/
public interface IAccountService {/*** 模拟保存账户*/void saveAccount();
}
/*** 账户的业务层实现类*/
public class AccountServiceImpl implements IAccountService {private  IAccountDao accountDao=new AccountDaoImpl();@Overridepublic void saveAccount() {accountDao.saveAccount();}
}
  1. 持久层接口和实现类
/*** 账户的持久层接口*/
public interface IAccountDao {/*** 模拟保存账户的操作*/void saveAccount();
}
/*** 账户的持久层实现类*/
public class AccountDaoImpl implements IAccountDao {@Overridepublic void saveAccount() {System.out.println("保存了");}
}
  1. 配置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>
  1. 运行结果
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的管理细节

  1. 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>
  1. Bean的作用范围调整
bean标签的scope属性作用:用于指定bean的作用范围取值:常用的就是单例的和多例的singleton:单例的(默认)prototype:多例的request:作用于web应用的请求范围session:作用于web应用的会话范围global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境的时候,它就是session

  1. 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.使用注解
  1. 构造器注入

 使用标签: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'
  1. 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
  1. 注入集合
复杂类型的注入/集合类型的注入用于给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相关推荐

  1. spring IOC和DI

    spring IOC and DI 1.IOC和DI的区别: IOC:对象的管理权由spring容器掌握(管理权限包括:对象的创建时间点.创建方式以及对象属性的管理): DI:spring操作对象属性 ...

  2. 手写实现Spring(IOC、DI),SpringMVC基础功能

    手写实现Spring(IOC.DI),SpringMVC功能 spring和springMVC的用法相信大家都不陌生,我简单讲下我实现的思路 spring阶段 事项 配置 配置web.xml: ini ...

  3. 浅谈Spring IOC和DI及Spring工厂类

    浅谈Spring IOC和DI及Spring的工厂类 文章目录 浅谈Spring IOC和DI及Spring的工厂类 一. IOC 1.什么是IOC 2.为什么使用IOC 传统开发模式的弊端 3. 使 ...

  4. Spring IOC与DI、反射的理解 含小案例说明

    阅览了很多篇博文,对于Spring IOC和DI看到很多人介绍的感觉都很含糊,读完之后还是觉得混淆的不行,也有的人认为DI是IOC的另一种说法-emm,可能个人理解不同吧,我的观点并不然.但这种东西, ...

  5. spring IOC和DI 理解

    IOC(控制反转)和DI(依赖注入)是spring中的重要组成部分,下面是个人的一些理解,不代表官方. 1.IOC是什么? IOC:全名是Inversion of Controller 中文解释是控制 ...

  6. Spring IOC和DI

    Spring  IOC和DI 框架:  将一些公用的模块进行集成,通过框架的形式进行管理(事务控制,权限控制(Shiro),日志收集log) Spring框架  SSH: Struts2(配置重型)+ ...

  7. Spring:IoC和DI完成打印机打印详细说明过程及代码

    Spring:IoC和DI完成打印机 课后作业 使用Spring的IoC.DI 装配一台打印机 纸张接口 实现 有: A4 A5 墨盒接口 实现 有:黑白 彩色 注解方式和非注解方式都要 说明:1.首 ...

  8. 关于RuoYi中Spring IOC、DI以及MVC不同注解的使用

    1.什么是Spring IOC.DI? IOC(inverse of control)即"控制反转",DI(Dependence Injection)即"依赖注入&quo ...

  9. 彻底理解Spring IOC和DI

    目录 前言 1. 分享Iteye的开涛对Ioc的精彩讲解 1.1 IoC是什么 1.2 IoC能做什么 1.3 IoC和DI 2. 分享Bromon的blog上对IoC与DI浅显易懂的讲解 2.1 I ...

  10. Spring IoC、DI、Bean和自动装配的理解

    文章目录 IoC创建对象 DI依赖注入 Bean的理解 自动装配 IoC创建对象 我们都知道IoC是控制反转的,也就是我们只需要把类注册到Spring容器中,他可以帮助我们创建对象,该创建的思想也就是 ...

最新文章

  1. 修改审查元素怎么保存_手机qq性别怎么改成空白
  2. MATLAB符号运算(3)
  3. layui 鼠标移入变为小手_如何在 LayUI 数据表格的列元素上,鼠标悬浮,显示所有文字内容(修改源码)...
  4. 缓存/内存型数据库 Redis
  5. python的sorted函数和operator.itemgetter函数
  6. 基于Springboot的旅游管理系统
  7. Robo3T连接远程mongodb
  8. 顶级区块链开发人员工具:涉及框架、IDE、安全工具、测试网络、区块链预言机和节点服务
  9. 网页在线PS网站源码PHP 浏览器在线P图
  10. 百度地图android兼容,支持离线地图 百度地图Android版上线
  11. 大数据可视化常用的方式有哪些
  12. SEO优化核心盘点,解谜、扫雷、权重提升统统在这
  13. 微软放弃收购雅虎猜想:杨致远代价不菲的胜利
  14. 我转行程序员的那一年(六)
  15. Poi HSSFCellStyle.ALIGN_CENTER VERTICAL_CENTER 等爆红的解决办法
  16. 聊聊手机之--小米6
  17. 拼多多怎么做?无货源新手怎么轻松上手?(小珏)
  18. java learn 日期
  19. Json 处理 - golang
  20. Unity使用全局钩子

热门文章

  1. ios内购php验证码,PHP (Laravel) 实现 iOS 内购服务端验证
  2. Microsoft SQL Server Management Studio 附加数据库时出错。有关详细信息,请单击……
  3. 11.4.9 MONTH(date)函数
  4. 小米MACE开源框架搭建
  5. 适用于mac的Tor浏览器?
  6. 计算机可移动磁盘自动启动,(在线求助)为什么一开机所有硬盘就自动设为默认共享?...
  7. 程序状态寄存器PSR
  8. 强烈质疑“步行1公里就能坐上地铁”
  9. 【Leetcode -1721.交换链表中的节点 -2058.找出临界点之间的最小和最大距离】
  10. 第三章:zigbee学习笔记之物理层和mac层帧格式分析