Summer——从头开始写一个简易的Spring框架
Summer——从头开始写一个简易的Spring框架
参考Spring框架实现一个简易类似的Java框架。计划陆续实现IOC、AOP、以及数据访问模块和事务控制模块。项目持续维护中...欢迎Star!Thanks~~~
本项目参考自Spring,但又做出了自己的创新,最大的创新点在于解决循环依赖的问题,引入了自己的解决方案,具体方法可以参考更新日志中Version 0.5(Pre-release)的更新记录。
项目计划:
- [x] IOC容器
- [x] AOP切面
- [x] 对外的扩展接口
- [ ] 数据访问集成模块(JDBC、事务控制)
关于对IOC和AOP功能为什么要使用(why),以及应该如何使用(how)请移步使用文档,要了解每个版本更新的内容请移步更新日志。
关于如何将自己的框架适配到summer,请查看如何适配summer。
运行环境
JDK 8
项目主要技术栈
注解、反射
如何使用
仓库地址: https://github.com/vfdxvffd/Summer
下载最新的jar包 ,将其导入项目中,即可使用,目录结构如下图,蓝色框内为
summer的核心代码,ch包下为logback日志依赖,net.sf.cglib下为cglib动态代理的依赖,org.slf4j下为slf4j的日志门面依赖。

Version 1.0(Release)
本次更新测试了之前的版本的稳定性,以及增加了框架的扩展性,开放出别的框架适配的接口。
- 对之前的
pre-release版本进行了多次测试以确保稳定性。 - 框架对外开放
Extension接口,该接口中的方法在ioc容器构造的多个阶段进行了切入,增加了框架的可扩展性。 - 如何将自己的框架适配到
Summer,请看如何适配summer或者可以提issues。
Version 0.5(Pre-release)
一次重大更新
bug描述:循环依赖的问题复现出来
因为之前v0.1更新中引入的一个解决bug的方法导致了这个重大的bug,这次通过设置二级缓存来解决循环依赖的问题,具体bug的产生原因详情可见更新日志,更新日志对这次bug的出现原因以及解决方法做了详细的说明。
bug解决:
针对目前掌握的代理方面的知识,对之前的做法做出一些调整。设置二级缓存,一级缓存一个(即真正的ioc容器),二级缓存两个,都是负责存放实例化但未初始化的对象,但一个是存放原对象,另一个负责存放代理对象,二级缓存的示意图如下:
将ioc容器的构造过程分为四步来进行:
- 遍历包,找到所有需要被IOC管理的类,封装成
BeanDefinition - 根据第一步获取到的
BeanDefinition实例化那些单例且非延迟加载的对象,并将其加入到二级缓存的earlyRealObjects中 - 对第二步得到的
earlyRealObjects中的对象进行检查,看是否需要设置代理,如果需要则对其进行代理,并将代理对象加入到二级缓存中的earlyProxyObjects中(并不删除earlyRealObjects中对应的真正的对象)。 - 对第二步得到的
earlyRealObjects中的对象进行注入工作(即开始进行初始化),检查每个对象的每个域,如果标注了@Autowired注解且值为null,则对其进行注入工作,现在一级缓存中查找,如果有直接取出为其注入,如果没有检查二级缓存的earlyProxyObjects,如果有则取出为其注入,如果没有则接着检查二级缓存的earlyRealObjects,找到后为其注入,此时如果还没有则说明这个域对应的bean是非单例(prototype)模式或者懒加载模式的,则为其实例化并设置代理(如果需要),并初始化,然后注入其中。如果是非ioc容器管理的域,则直接注入null,也可以考虑改为抛出异常给用户提示。
Version 0.4(Pre-release)
本次更新加入了新功能,修改了一个已知的bug
本次更新引入
CGLib依赖,增加动态代理的方式,对于实现了接口的方法采用JDK动态代理来实现切面功能,对于没有实现接口的类采用CGLib来实现切面。
修改bug,之前版本中的
判断当前类是否已经完成了实例对象全部的创建注入工作的方法,判断没有包含所有情况。bug描述:对于一个没有任何域
且需要代理的对象,进行注入工作的时候会由于没有域需要注入,从而直接判断其已经完成注入,而跳过了代理阶段。
Version 0.3(Pre-release)
本次更新引入了日志依赖,增加了对ioc构造过程中的日志记录

对于标注了
@Aspect注解的类自动将其加入IOC容器中,不用再重复标注注解
Version 0.2(Pre-release)
本次更新加入了一些新功能,修复了一些bug
更新功能:
aop增加了一种切入方式,目前有以下切入方式
@Before、@AfterReturning、@AfterThrowing、@After以上对应的切入时机如下:
try {
@Before
fun.invoke();
@AfterReturning
} catch (Throwable t) {
@AfterThrowing
} finally {
@After
}
切面方法可以通过
JoinPoint类获取被切的方法的参数、方法名、返回值类型。对于@AfterReturning的切入方式可以获取返回值,类型为Object,而@AfterThrowing可以获取抛出的异常,类型为Throwable。
修复了重复代理的bug
bug描述:当一个待注入bean中有超过一个需要注入的域(带有注解@Autowired且未完成赋值),如果对它中的方法进行切面,这时切面方法会重复执行
Version 0.1(Pre-release)
本次更新主要修复了一些bug,以及优化了代码的结构
修复对于注入对象的切面方法失效的bug
bug描述:在controller中注入service,但是如果有对于service的切面方法,则切面方法无法被调用
修复延迟加载的对象注入失败的bug
bug描述:对于标注了延迟加载的类注入时会发生异常
修复对非单例的bean注入失败的bug
bug描述:对于标注了非单例的类注入时会发生异常,且会调用多次构造函数的问题
增加核心代码的注释。
优化代码结构,重构了大部分冗余的代码块
抽取可重用方法。
Version 0.0(Pre-release)
完成IOC容器的初步搭建
完成AOP功能的简单使用(还需修改)
支持
@Component、@Autowired、@Qualifier、@Value、@Repository、@Service、@Controller注解的使用- @Component(同@Respository、@Service、@Controller):标注在类上,将此类注册到ioc容器中
- @Autowired:自动注入ioc容器中的对象
- @Qualifier:自动注入ioc中对象的时候指定
beanName,如不指定则按照beanType注入 - @Value:指定将类注入到容器是基本类型(包括包装类)字段的值
支持根据
beanName、beanType获取ioc中的对象自定义类型转化异常,
@Value接受String类型,如果传入的值并不能正确转化,就抛出DataConversionException异常。增加单例模式与非单例模式的配置注解
@Scope,以及增加延迟加载的配置注解@Lazy可以使用接口来接受IOC中返回的对象
AOP可以对方法进行
@Before、@After、@AfterThrowing的切面,需要配置方法的全方法名AOP使用JDK的动态代理,
set可以不添加,内部实现是直接通过设置域的可访问属性,然后直接设置值后续计划:
- 支持根据
xml配置ioc容器中的对象 - 对于运行过程可能发生的异常使其尽可能可控,且明确的抛出或处理
- 对于AOP可选择性的加入
CGLIB代理 - 对于AOP一些已注入对象的代理失效bug进行修复(已定位)
- etc... for more...
- 支持根据
Summer——从头开始写一个简易的Spring框架的更多相关文章
- 造轮子:实现一个简易的 Spring IoC 容器
作者:DeppWang.原文地址 我通过实现一个简易的 Spring IoC 容器,算是入门了 Spring 框架.本文是对实现过程的一个总结提炼,需要配合源码阅读,源码地址. 结合本文和源码,你应该 ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- go server框架学习之路 - 写一个自己的go框架
go server框架学习之路 - 写一个自己的go框架 用简单的代码实现一个go框架 代码地址: https://github.com/cw731/gcw 1 创建一个简单的框架 代码 packag ...
- 动手写一个简单的Web框架(模板渲染)
动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...
- 动手写一个简单的Web框架(Werkzeug路由问题)
动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...
- 动手写一个简单的Web框架(HelloWorld的实现)
动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...
- 手写一个简易的IOC
这个小项目是我读过一点Spring的源码后,模仿Spring的IOC写的一个简易的IOC,当然Spring的在天上,我写的在马里亚纳海沟,哈哈 感兴趣的小伙伴可以去我的github拉取代码看着玩 地址 ...
- 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)
预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...
- 如何用 Python 写一个简易的抽奖程序
不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...
随机推荐
- 电影AI修复,让重温经典有了新的可能
摘要:有没有一种呈现,不以追求商业为第一目的,不用花大价钱,不用翻拍,没有画蛇添足,低成本的可共赏的让经典更清晰? 本文分享自华为云社区<除了重映和翻拍,重温经典的第三种可能>,原文作者: ...
- 设计模式—singleton(单例模式)
单例模式 单例设计模式属于创建型模式,它提供了一种创建对象的最佳方式.这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建. 这个类提供了一种访问其唯一的对象的方式,可以直接 ...
- python函数之有参装饰器
一.为什么要有有参装饰器? 来看之前的无参装饰器 # 无参装饰器 def outter(func): def wrapper(*args,**kwargs): start = time.time() ...
- 封装Vue纵向表头左右结构的table表格
我们前端开发人员在使用表格的过程中,大概率碰到的都是表格头部在表格的最上边,然后呈一行展示,紧接着就是表格的每一行的每一个单元格来展示具体内容的场景,很少会遇到表格的头部呈纵向一行展示,也就是说表格的 ...
- CentOS7 搭建 K8S 环境
前期准备 环境规划 K8S 与Docker兼容问题 k8s v1.18.0 => Docker v18.x k8s v1.19.0 => Docker v19.x 软件 版本 Linux操 ...
- [递推]D. 【例题4】传球游戏
D . [ 例 题 4 ] 传 球 游 戏 D. [例题4]传球游戏 D.[例题4]传球游戏 题目解析 设 t ( i , j ) t(i,j) t(i,j)为过了 j j j轮,轮到 i i i手上 ...
- [递推]C. 【例题3】数的划分
C . [ 例 题 3 ] 数 的 划 分 C. [例题3]数的划分 C.[例题3]数的划分 题目描述 将整数 n n n 分成 k k k 份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例 ...
- 第一个真正的 GUI 程序——Tkinter教程系列02
第一个真正的 GUI 程序--Tkinter教程系列02 前言 欢迎光临我的个人博客 chens.life Tk 系列教程: Tkinter教程系列01--引言和安装Tk 我们将编写一个英尺和米的转换 ...
- Azure DevOps 跨账号连接 Azure 服务
一,引言 由于新申请的 Azure DevOps 账号中的私有项目不在享受托管代理提供的1800分钟的免费时间,又不想花钱付费,那我们只能另想版本解决没有并行作业的问题. -------------- ...
- day-02-循环
while 循环 why:大气循环, 吃饭,上课,睡觉,日复一日,歌曲列表循序环,程序中:输入用户名密码, what:while 无限循环. how: 基本结构: while 条件: 循环体 初识循环 ...