运维.售后
论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
博客
Blog
ToB门户
了解全球最新的ToB事件
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
ToB企服应用市场:ToB评测及商务社交产业平台
»
论坛
›
数据库
›
Mysql
›
Spring入门系列:浅析知识点
Spring入门系列:浅析知识点
滴水恩情
金牌会员
|
2023-4-10 12:41:02
|
显示全部楼层
|
阅读模式
楼主
主题
916
|
帖子
916
|
积分
2748
前言
讲解Spring之前,我们首先梳理下Spring有哪些知识点可以进行入手源码分析,比如:
Spring IOC依赖注入
Spring AOP切面编程
Spring Bean的声明周期底层原理
Spring 初始化底层原理
Spring Transaction事务底层原理
Hello World
通过这些知识点,后续我们慢慢在深入Spring的使用及原理剖析,为了更好地理解Spring,我们需要先了解一个最简单的示例——Hello World。在学习任何框架和语言之前,Hello World都是必不可少的。
//在以前大家都是spring.xml进行注入bean后供Spring框架解析
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();
复制代码
spring.xml中的内容为:
[/code]如果对上面的代码或者xml形式很陌生,再看下面一种代码,也是目前流行的一种形式
[code]//通过我们的配置类进行注入bean并解析
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);
//ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test()
复制代码
MySpringConfig中的内容为:
@ComponentScan("com.xiaoyu")
public class MySpringConfig {
@Bean
public UserService userService(){
return new UserService();
}
}
复制代码
相信很多人都会对上面的代码不陌生,那我们来看下这三行代码都做了那些工作:
构造一个ClassPathXmlApplicationContext类解析配置文件 或者AnnotationConfigApplicationContext类 解析配置类,那么调用该构造方法除开会实例化得到一个对象,还会做哪些事情?
从context中获取一个名字为"userService"的userService对象,那么为什么输入一个字符串就可以得到对象呢,好像跟Map有些类似,getBean()又是如何实现的?返回的UserService对象和我们自己直接new的UserService对象有区别吗?
通过获取到的UserService对象调用test方法,这个不难理解。
虽然我们目前很少直接使用这种方式来使用Spring,而是使用Spring MVC或者Spring Boot,但是它们都是基于上面这种方式的,都需要在内部去创建一个
ApplicationContext的,只不过:
Spring MVC创建的是XmlWebApplicationContext,和ClassPathXmlApplicationContext类似,都是基于XML配置的
Spring Boot创建的是AnnotationConfigApplicationContext
下面我们将重点讲解Spring对bean的创建,也就是大家常说的Bean的生命周期。虽然我们只是入门级别的学习,但我们仍将深入探讨流程,但不会涉及到具体的源码分析。在后续的源码分析系列中,我们将着重分析每一个知识点。
Bean的创建过程
那么,Spring是如何创建一个Bean的呢?这就是Bean的生命周期。其大体过程如下:
首先当我们的对象类被配置类使用@Bean又或者被包路径扫描到将会进入创建Bean的流程
Spring会使用对象构造器进行实例化创建个对象
开始解析对象的属性是否有被@autowired注解修饰,如果有会从Spring的单例池中获取对象并进行注入就是属性赋值(依赖注入)
依赖注入后会判断对象时否实现了各种Aware接口,如:BeanNameAware接口、 BeanClassLoaderAware接口、BeanFactoryAware接口等,并自动调用其中的需要被实现的方法(Aware回调)
回调方法实现后,Spring会判断是否有包含了@postconstruct注解方法,如果有会进行调用此方法(实例化前)
Spring判断对象是否实现了InitializingBean接口,实例化对象就必须调用afterPropertiesSet()方法,也是Spring帮调用的(初始化)
最后,Spring会判断我们的对象是否需要进行AOP,如果不需要那么Bean到此就完事,如果需要,Spring还会自动动态代理并生成一个代理对象做为Bean(初始化后)
通过以上步骤,我们可以了解到创建的对象可能存在两种结果。如果不需要AOP,Bean就是通过构造方法创建的对象;如果需要AOP,Bean就是代理类所实例化得到的对象,而不是构造方法所得到的对象。
Bean创建后:
如果当前Bean是单例的(默认),Spring在初始化Bean之后,会将当前已经初始化之后的对象放入Spring管理的单例缓存池中(Map结构),这样如果其他对象需要注入这个对象时,会直接从单例缓存池中取出来,进行属性注入。
如果当前Bean是多例的(即被@Scope("prototype")注解修饰),每次获取对象时,或者被其他对象引用时都会重新走一遍创建Bean的逻辑来创建一个新对象。这意味着,每次获取该Bean时都会创建一个新的实例,而不是从缓存池中获取已有的实例。因此,多例Bean的对象是不共享的,每个对象都是独立的。
构造器的初始化
在Spring中,每个对象都会有默认的构造器。但是在实际业务中,有时候会存在多个构造器的情况。那么,Spring如何去选择使用哪个构造器去创建对象呢?
Spring的判断逻辑如下:
如果当前bean有且仅有一个的构造器,那么直接使用这个构造器创建对象。不管它是有参还是无参。
如果存在多个构造器,Spring会从中选择一个无参构造器进行创建对象,如果没有无参构造器,那么直接报错。
Spring的设计思想是这样的:
如果只有一个构造器,那么没有选择,只能使用这个构造器
如果有多个,只选择没有入参的构造器,因为无参构造方法本身表示了一种默认的意义
还要一种就是使用了@Autowired注解修饰,那么就表示人工干预 了Spring选择的权利,直接选择程序员指定的构造器,如果有参,里面的参数bean对象(单例)会从单例缓存池中取。
a.先按照bean类型进行查找,如果只找到一个实例,那么直接注入。
b.如果找到多个实例,那么会进行匹配入参name名字来确定唯一一个实例。
c如果没有找到,则会报错,无法创建当前Bean对象
综上所述,Spring会根据Bean的构造器情况进行选择,如果需要人工干预,可以使用@Autowired注解修饰。
AOP的大致流程
在创建对象时,Spring会判断当前对象是否需要进行AOP代理。为了确定当前Bean对象是否需要代理,大致流程如下:
Spring启动时寻找所有使用@AspectJ注解的切面Bean对象
搜索切面bean的各个方法是否有包含了@Before、@After、@Around注解。
检查当前Bean或方法是否符合我们编写的Pointcut切面条件。
Spring创建代理对象通常采用cglib代理,JDK代理是另一种模式。后续我们会详细分析此逻辑。
具体流程如下:
首先当前bean被确认为需要进行代理,将会生成BeanProxy对象,而不是我们构造出来的Bean。
当前BeanProxy会重写符合切面方法的方法
当前BeanProxy被依赖注入时,给其他Bean的属性赋值时也会是代理对象。
BeanProxy代理对象都有一个target属性,用于注入被代理对象,即我们正常构造并进行属性注入的Bean对象
当BeanProxy的切面方法被调用时,首先调用我们编写的切面逻辑,然后调用被代理对象的方法(即我们编写的业务方法)。这里也不太准确,具体得看你写的什么样的切面注解,不过大致都是这样来调用的链路。
Spring事务
一谈到事务,大家首先想到的肯定是@Transaction注解,而这种注解也会被Spring创建对象时检测到,然后会生成代理对象,这种方式其实工作中用到的也特别多,用起来也特别爽,那我们也大概讲下事务的逻辑处理吧,其大致流程如下:
首先如果当前Bean有@Transaction注解,那么当前bean会成为代理对象。
当被调用到具体的方法时。Spring则会利用事务管理器TransactionManage获取一个数据库连接。
直接将当前数据库连接的自动提交关闭,autocommit=false。
开始执行我们的业务方法,执行业务SQL操作。
如果执行完方法后,没有异常则提交事务,如果出现异常则进行回滚。
以上是简单的事务处理流程,深入细节会涉及到Spring的事务传播级别,如果现在说的话,会陷入不必要的思考,自此我们的 [Spring入门系列] 也结篇了,在接下来的 [Spring源码系列] 中,我将更加详细地讲解这些内容。
「准备开车,可坐稳了别被摔下来」
先对这些流程有个印象,并带着疑惑来进一步探究Spring的内部机制,好了,今天就讲到这里,我是小雨,我们下期再见。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
使用道具
举报
0 个回复
正序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
发新帖
回复
滴水恩情
金牌会员
这个人很懒什么都没写!
楼主热帖
体系集成商重返黄金年代
SFSafariViewController 加载的网页与 ...
ubuntu 20.04 安装好搜狗输入法无法输 ...
nsenter命令简单介绍
未来数据库需要关心的硬核创新 ...
Spark快速上手(2)Spark核心编程-RDD简 ...
使用扩展函数方式,在Winform界面中快 ...
Kali Linux全网最细安装教程
【C++】STL——vector模拟实现
Linux 进程概念 (上)
标签云
存储
服务器
快速回复
返回顶部
返回列表