Spring入门系列:浅析知识点
前言
讲解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中的内容为:
<context:component-scan base-package="com.zhouyu"/>
<bean id="userService" class="com.zhouyu.service.UserService"/>
如果对上面的代码或者xml形式很陌生,再看下面一种代码,也是目前流行的一种形式
//通过我们的配置类进行注入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<String,Object>有些类似,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的内部机制,好了,今天就讲到这里,我是小雨,我们下期再见。

Spring入门系列:浅析知识点的更多相关文章
- Spring入门(一):创建Spring项目
本篇博客作为Spring入门系列的第一篇博客,不会讲解什么是Spring以及Spring的发展史这些太理论的东西,主要讲解下如何使用IntelliJ IDEA创建第一个Spring项目以及通过一个示例 ...
- spring cloud 入门系列四:使用Hystrix 实现断路器进行服务容错保护
在微服务中,我们将系统拆分为很多个服务单元,各单元之间通过服务注册和订阅消费的方式进行相互依赖.但是如果有一些服务出现问题了会怎么样? 比如说有三个服务(ABC),A调用B,B调用C.由于网络延迟或C ...
- spring cloud 入门系列一:初识spring cloud
最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubbo和spring cloud之间我选择了从spring cloud,主要有如下几种原因: dubbo主要专注于微服务中的一个环节--服务 ...
- spring cloud 入门系列:总结
从我第一次接触Spring Cloud到现在已经有3个多月了,当时是在博客园里面注册了账号,并且看到很多文章都在谈论微服务,因此我就去了解了下,最终决定开始学习Spring Cloud.我在一款阅读A ...
- Spring实践系列-入门篇(一)
本文主要介绍了在本地搭建并运行一个Spring应用,演示了Spring依赖注入的特性 1 环境搭建 1.1 Maven依赖 目前只用到依赖注入的功能,故以下三个包已满足使用. <properti ...
- Spring Boot入门系列(十三)如何实现事务
前面介绍了Spring Boot 中的整合Mybatis并实现增删改查.不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1 ...
- Spring Boot入门系列(十六)使用pagehelper实现分页功能
之前讲了Springboot整合Mybatis,然后介绍了如何自动生成pojo实体类.mapper类和对应的mapper.xml 文件,并实现最基本的增删改查功能.接下来要说一说Mybatis 的分页 ...
- Spring Boot入门系列(十七)整合Mybatis,创建自定义mapper 实现多表关联查询!
之前讲了Springboot整合Mybatis,介绍了如何自动生成pojo实体类.mapper类和对应的mapper.xml 文件,并实现最基本的增删改查功能.mybatis 插件自动生成的mappe ...
- Spring Boot入门系列(二十)快速打造Restful API 接口
spring boot入门系列文章已经写到第二十篇,前面我们讲了spring boot的基础入门的内容,也介绍了spring boot 整合mybatis,整合redis.整合Thymeleaf 模板 ...
- spring cloud 入门系列
springcloud入门总结转发自:https://www.cnblogs.com/sam-uncle/p/9340390.html 最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubb ...
随机推荐
- 第16章 发布和部署应用程序(ASP.NET Core in Action, 2nd Edition)
本章包括 发布 ASP.NET Core 应用程序 在 IIS 中托管 ASP.NET Core 应用程序 自定义 ASP.NET Core 应用程序的 URL 通过捆绑和缩小优化客户端资源 到目前为 ...
- 如何卸载inventor 2023?怎么把inventor彻底卸载删除干净重新安装的方法【转载】
inventor 2023卸载重新安装方法,使用清理卸载工具箱完全彻底删除干净inventor 2023各种残留注册表和文件.inventor 2023显示已安装或者报错出现提示安装未完成某些产品无法 ...
- springboot配置类@ConfigurationProperties报错Not registered via @EnableConfigurationProperties or marked as Spring component
添加一个@Component可以解决此问题,只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能.
- spring boot 中 CommandLineRunner接口使用
接口定义:接口,用于指示bean包含在SpringApplication中时应运行.可以在同一应用程序上下文中定义多个CommandLineRunner bean,并可以使用ordered接口或@Or ...
- SpringBoot - Lombok使用详解4(@Data、@Value、@NonNull、@Cleanup)
六.Lombok 注解详解(4) 8,@Data (1)@Data 是一个复合注解,用在类上,使用后会生成:默认的无参构造函数.所有属性的 getter.所有非 final 属性的 setter 方法 ...
- Python - XSS-href
参考资料: https://owasp-skf.gitbook.io/asvs-write-ups/cross-site-scripting-href-xss-href/kbid-3-cross-si ...
- Using Semaphores in Delphi, Part 2: The Connection Pool
Abstract: Semaphores are used to coordinate multiple threads and processes. That semaphores provide ...
- unittest框架基本使用
1.简介 unittest是python内置的单元测试框架,具备编写用例.组织用例.执行用例.输出报告等自动化框架的条件.使用unittest前需要了解该框架的五个概念: 即test case,tes ...
- format UTF-8 BOM by AX
#File CommaTextIo commaTextIo; FileIOPermission permission; CustTable custTable; str fileName = @&qu ...
- The Ultimate Guide to Dynamics 365 Pricing and Licensing
Microsoft Dynamics 365 integrates powerful ERP and CRM capabilities in the cloud to provide busi ...