前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从一个互联网职场小白到一个沪漂湿人,一路让我知道分享是一件多么重要的事情,总之不对的地方,多多指出,我们一起徜徉代码的海洋!

我这里做每个章节去说的前提,不是一定很标准的套用一些官方名词,目的是为了让大家可以理解更加清楚,如果形容的不恰当,可以留言出来,万分感激

1、反转(转移)控制(Inverse of Control)

所谓反转控制,就是我们常说的IOC,大学老师经常告诉我们,ioc就是反转控制,就是控制反转,一头雾水你也听不明白,听我说来

我们在没有spring的时候,对于对象的创建,我们是在代码里做这个事情的,new 对象,既然我们需要让spring来托管对象,我们引出下面的概念

  • 控制:对于成员变量赋值的控制权
  • 反转控制:把对于成员变量赋值的控制权,从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成
  • 好处:解耦合
  • 底层实现:工厂设计模式

我画了一张图,就可以描述很清楚

对于成员变量赋值的控制权==Spring配置文件+Spring工厂(ApplicationContext)

2、依赖注入

依赖注入是Spring的编程方式,简称DI(Dependency Injection)

  • 注入:通过Spring的⼯⼚及配置⽂件,为对象(bean,组件)的成员变量赋值
  • 依赖:当⼀个类需要另⼀个类时,就意味着依赖,⼀旦出现依赖,就可以把另⼀个类作为本
    类的成员变量,最终通过Spring配置⽂件进⾏注⼊(赋值)。

我的UserService是需要访问数据库对吧,所以我必须要有数据库的操作UserDao,没他不行,非他不可!这就叫做依赖!

我需要你的时候,等于我就要依赖你,所以我们就可以按照依赖注入的想法,当然你要提供set方法,我就可以把你注入进来,把你做为我的成员变量,进而我们可以通过Spring配置文件,注入进来!

所以面试不会问这个概念,而属于一种Spring的思想。

好处:解耦合!

3、Spring工厂创建复杂对象

3.1、什么是简单对象

指的是可以直接通过new构造方法,来创建对象,反射底层,也是调用构造方法。

3.2、复杂对象

不能直接通过new创建,比如Connection,SqlSessionFactory对象,这种对象不能直接new,创建过程比较复杂。

所以我们希望Spring既能帮我们创建简单对象,也可以帮我们创建复杂对象,这样Spring是不是就可以帮我们创建一切对象了?

3.3、Spring工厂创建复杂对象的三种方式

既然知道Spring要创建复杂对象,那么他有几种方式呢,下面我们来认识下:

  • FactoryBean接口

1、开发步骤

实现FactoryBean接口

getObject:用于书写创建复杂对象的代码,并把复杂对象作为方法的返回值返回出去

类似哪些需要在这里创建呢,比如Connection,SqlSessionFactory

getObjectType:同理上面创建什么样的复杂对象,就返回什么样的复杂对象对应的Class对象

isSingleton:如果这个复杂对象只需要创建一次,返回true;如果这个复杂对象每一次调用都需要创建一个新的对象,返回false;

public class ConnectionFactoryBean implements FactoryBean {/*** 用于书写创建复杂对象的代码,并把复杂对象作为方法的返回值返回出去*/@Overridepublic Object getObject() throws Exception {return null;}/*** 返回所创建复杂对象的Class对象* @return*/@Overridepublic Class<?> getObjectType() {return null;}/*** 如果这个复杂对象只需要创建一次的话,返回true* 如果这个复杂对象每一次调用都需要创建一个新的对象,返回false* @return*/@Overridepublic boolean isSingleton() {return false;}
}

所以Spring把这个复杂对象的创建过程交给了用户去自定义复杂对象!


public class ConnectionFactoryBean implements FactoryBean<Connection> {/*** 用于书写创建复杂对象的代码,并把复杂对象作为方法的返回值返回出去*/@Overridepublic Connection getObject() throws Exception {Class.forName("com.mysql.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false","root","root");return connection;}/*** 返回所创建复杂对象的Class对象* @return*/@Overridepublic Class<?> getObjectType() {return Connection.class;}/*** 如果这个复杂对象只需要创建一次的话,返回true* 如果这个复杂对象每一次调用都需要创建一个新的对象,返回false* @return*/@Overridepublic boolean isSingleton() {return false;}
}

applicationContext.xml配置文件如下

<!--如果Class中指定的类型 是FactoryBean接⼝的实现类,那么通过id值获得的是
这个类所创建的复杂对象Connection-->
<bean id="conn" class="com.chenxin.spring5.factorybean.ConnectionFactoryBean"></bean>

看看结果对不对

conn = com.mysql.jdbc.JDBC4Connection@481a15ff

思考下,咦为毛是Connection对象,我不是应该是获取ConnectionFactoryBean对象吗?

想想我们要得到的结果是不是Connection对象?所以Spring在这个实现FactoryBean接口上,就发生了变化,此时你再通过工厂创建对象,Spring就不会按照你以为的那样,给你一个ConnectionFactoryBean对象,而是真正给你一个你要创建的复杂对象!

细节:

1、如果就想获得FactoryBean类型的对象 ctx.getBean("&conn") 获得就是ConnectionFactoryBean对象

2、isSingleton⽅法 返回 true-只会创建⼀个复杂对象,返回false--每⼀次都会创建新的对象

问题:用户需要根据这个对象的特点 ,决定是返回true还是false ,(SqlSessionFactory返回true比较合理,因为是重量级对象,只用一个即可,不存在Connection的问题), (Connection也是一样,是不是每次都需要创建连接对象,连接对象是不能被公用的,因为有可能会有事务的操作,比如,有个conn1,第一个客户t1,t1开启了事务,开始运行,此时第二个用户t2也拿到连接conn1,也开启了事务,如果t1执行的快,直接提交了,那么t2就会被影响,所以对吧!)

3、mysql⾼版本连接创建时,需要制定SSL证书,解决问题的⽅式

4、依赖注入的体会:对于URL,username,password,是不是在ConnectionFactoryBean中是非常重要的,是需要依赖这些字符串的对吧,既然是依赖,我就可以作为我的成员变量,通过Spring的配置文件来完成注入,赋值,所以我们可以修改下代码


public class ConnectionFactoryBean implements FactoryBean<Connection> {private String driverClassName;private String url;private String username;private String password;public void setDriverClassName(String driverClassName) {this.driverClassName = driverClassName;}public void setUrl(String url) {this.url = url;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}/*** 用于书写创建复杂对象的代码,并把复杂对象作为方法的返回值返回出去*/@Overridepublic Connection getObject() throws Exception {Class.forName(driverClassName);Connection connection = DriverManager.getConnection(url, username, password);return connection;}/*** 返回所创建复杂对象的Class对象** @return*/@Overridepublic Class<?> getObjectType() {return Connection.class;}/*** 如果这个复杂对象只需要创建一次的话,返回true* 如果这个复杂对象每一次调用都需要创建一个新的对象,返回false** @return*/@Overridepublic boolean isSingleton() {return false;}
}

配置文件改为

<bean id="conn" class="com.chenxin.spring5.factorybean.ConnectionFactoryBean"><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/users?useSSL=false"></property><property name="username" value="root"></property><property name="password" value="root"></property></bean>

这样结果是不是一样的?所以这里还是体会了依赖注入的思想!解耦合。

相信到这很多人会有疑问,我们来分析下

1、为什么Spring规定FactoryBean接口,实现,并且要把复杂对象的创建代码写在getObject里?

实际上有个东西叫做接口回调!任何开源框架内,反射+接口回调,什么都能做!

说明下,我们在学java基础的时候学过instanceof判断两个对象是否属于同一个类型的,Spring在拿到bean标签id=conn的时候,会判断当前这个ConnectionFactoryBean这个类是不是FactoryBean的子类,如果不是的话,就说明是简单对象,Spring直接帮我们new就可以了;如果是的话,那么你肯定就要实现三个方法,getObject,getObjectType和isSingleton,既然你实现了,Spring就能找到getObject方法,Spring就能调用这个方法,就可以获取到这个连接对象Connection;于是就可以返回出去。有人肯定会问,你怎么知道是Spring调用的,很明显你要是自己调用,你肯定要写new ConnectionFactoryBean(),然后自己去getObject方法,但是你知道你并没有这么做,所以是Spring按照约定来调用的!

总结:Spring中⽤于创建复杂对象的⼀种⽅式,也是Spring原⽣提供的,后续讲解Spring整合其他框架,也是⼤量应⽤FactoryBean;

  • 实例工厂

为什么有了FactoryBean,Spring还要整个实例工厂呢,原因以下几点

1、避免框架的侵入

如果选择Spring框架进行复杂对象开发的话,我们要实现FactoryBean接口,如果哪天我离开了Spring框架呢,那么之前实现FactoryBean接口的代码就没法用了

实际上FactoryBean接口输入Spring框架的侵入

2、整合遗留系统:比如我现有公司已经有了一个ConnectionFactory,里面有个getConnection方法已经可以帮我们获取Connection对象了,给我们的是class文件,我们只能拿到class文件

那么我们没法通过改源码的方式来进行创建复杂对象,所以我们有了实例工厂

遗留代码比如:

public class ConnectionFactory {public Connection getConnection(){Connection conn = null;try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false", "root", "root");}catch (Exception e){e.printStackTrace();}return conn;}
}

类和工厂实际上以前公司代码已经有了, 我们只需要去解决配置文件的问题

先把这个ConnectionFactory对象由Spring创建出来,进而要创建connection连接对象的时候,再通过Spring来关联这个ConnectionFactory工厂,调用getConnection方法,来得到connection对象

<!--  先交给Spring工厂创建这个工厂的对象  --><bean id="connectionFactory" class="com.chenxin.spring5.factorybean.ConnectionFactory"></bean><!--  然后把之前的ConnectionFactory和Spring整合进来,让Spring帮忙创建这个conn对象  --><bean id="conn" factory-bean="connectionFactory" factory-method="getConnection"></bean>
  • 静态工厂

作为静态工厂,和实例工厂的区别,体现在这个getConnection方法是不是静态的

public class StaticConnectionFactory {public static Connection getConnection(){Connection conn = null;try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/users?useSSL=false", "root", "root");}catch (Exception e){e.printStackTrace();}return conn;}
}

之前我们通过new ConnectionFactory().getConnection()得到对象,这里就是直接StaticConnectionFactory.getConnection()即可

所以配置文件这么写就可以了

    <bean id="connectionFactory" class="com.chenxin.spring5.factorybean.StaticConnectionFactory" factory-method="getConnection"/>

三种方式我这边就讲解完了!

4、Spring创建工厂总结

Spring即可以创建简单对象,也可以创建复杂对象,目的都是为了解耦!如果看了我前面两集讲解的Spring,这张图你一定会很清楚!

下一节我们来分析Spring创建工厂的次数是如何控制的,敬请期待!

Spring基础专题——第三章(反转控制与依赖注入)相关推荐

  1. 【Spring 工厂】反转控制与依赖注入、Spring工厂创建复杂对象3种方式

    反转控制与依赖注入 反转控制 与 依赖注入 反转控制(IOC Inverse of Control) 依赖注入 (Dependency Injection - DI) Spring工厂创建复杂对象(3 ...

  2. Spring基础专题——第七章(持久层整合)

    前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...

  3. Spring基础专题——第十一章(高级注解编程完结)

    前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...

  4. Spring基础专题——第五章(Aop代理)

    前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...

  5. Spring基础专题——第六章(Aop编程)

    前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...

  6. Spring事务专题(三)事务的基本概念,Mysql事务处理原理

    我重新整理了大纲,思考了很久,决定单独将MySQL的事务实现原理跟Spring中的事务示例分为两篇文章,因为二者毕竟没有什么实际关系,实际上如果你对MySQL的事务原理不感兴趣也可以直接跳过本文,等待 ...

  7. java-12:spring MVC - 控制反转IOC,依赖注入DI

    学习spring框架之前,先理解几个概念: 1.第一部分:依赖倒置原则 2.第二部分:控制反转,控制反转容器(实例) 3.第三部分:控制反转,控制反转容器(全面理解,面试题) 综合性理解:控制反转(I ...

  8. 三大框架之spring框架+IoC控制反转、DI依赖注入

    三大框架:业务层框架Spring+IoC+DI 往期文章:jsp与cookie.重定向与RESTFul架构支持 下一章节: 持久层框架MyBatis 初识Spring框架 MyBatis 入门http ...

  9. 详解spring的IOC控制反转和DI依赖注入

    转载 详解spring的IOC控制反转和DI依赖注入 2018-06-05 15:45:34 jiuqijack 阅读数 2945 文章标签: spring IOC控制反转 DI依赖注入 更多 分类专 ...

最新文章

  1. 拖拽批量上传图片如何保证 顺序_使用 Eagle 探索图片管理新边界
  2. Android开发之 adb 启动问题或是部署应用不成功,出现“The connection to adb is down, and a severe error has occured.”错误...
  3. __asm__ __volatile__(: : :memory)
  4. 新型机器人模拟蜻蜓飞行可以乱真!
  5. 《精益软件度量——实践者的观察与思考》—第1章1.1节精益软件开发的度量体系...
  6. pandas中inplace_pandas回顾小结(二)
  7. UIKeyboard键盘相关知识点
  8. android studio 使用问题 解决方法
  9. ★LeetCode(448)——找到所有数组中消失的数字(JavaScript)
  10. 7.PL_SQL——在PL_SQL程序中内嵌查询语句、DML语句、事物处理语句和游标属性
  11. 数据通路习题分析之二
  12. 华硕笔记本触摸鼠标手势无效怎么办
  13. 大数据时代下的办公自动化系统
  14. pip学习20200810
  15. FAT文件系统详解(二)
  16. APP微信支付java demo
  17. python的array是什么意思_[:,:]在NumPy数组上是什么意思
  18. 2021年吹过的牛都实现了吗?2022年你又期待遇见怎样的自己?
  19. Mysql中的常用类型 说明
  20. H.265/HEVC简介

热门文章

  1. 「倒计时」2021年移动云 API 应用创新开发大赛,你居然还没报名?!
  2. 从0开始,基于Python探究深度学习神经网络
  3. 明年,我要用 AI 给全村写对联
  4. 给AI系统做“安全体检”,阿里安全提出自动化AI对抗平台CAA | AAAI 2021
  5. 看清头秃元凶,腾讯AI首度揭示真相
  6. 编程能力差,90%输在了这点上!CTO:这样学编程 ,更容易成为高手
  7. 华人计算机视觉科学家黄煦涛逝世,众多AI大牛发文缅怀
  8. 自动机器学习:团队如何在自动学习项目中一起工作?(附链接)
  9. 知乎算法团队负责人孙付伟:Graph Embedding在知乎的应用实践
  10. 阿里AI摘图像识别竞赛WebVision桂冠,万物识别准确率创世界纪录