0.3、Spring源码学习-从一个UML模型讲起

1、前言

体能状态先于精神状态,习惯先于决心,聚焦先于喜好。

2、本文的灵感

最近的几个星期笔者在工作开发和Sping 源码学习中看到了一些“新奇”的代码写法,与此产生了一些灵感。

开发中遇到的情况是这样的,笔者需要对一个对账功能进行改造,现有程序有两个特点,一个是对账功能无法指定时间,由定时任务调用,总是生成昨天的定时任务;第二个特点是由于对接了多家公司,而每个公司对账形式又不相同。改造的点在于需要提供一个接口,允许按照指定日期生成对账文件,但是不能影响原有的功能。
正常来说,我需要新增一个以时间作为入参的方法即可。但是这样做的话每个公司的对账逻辑我都需要进行变动——系统现存的定时任务调用的方法并没有入参。
惊奇的是我发现代码结构使用了 接口-父类-子类 的形式,其中父类中提供了 private 修饰的时间参数和 get、set 方法,与此同时接口中有给时间赋值的抽象方法
这样一来我的改造思路就变为了-先调用给时间赋值的方法,然后调用原先的对账文件的方法,跟踪代码逻辑可以发现,需要将系统中获取时间的地方全部由“获取昨天”修改为“如果时间参数为空则获取昨天,否则就获取指定的时间参数”-在工具类中增加这个方法即可,然后重构测试后就搞定了

在查看Spring 源码的过程中,发现了这样的情况,Spring 的顶层是接口,有些接口甚至是没有抽象方法的,然后这些接口被子类实现,子类又有新的子类,这样也可以简化出一个 接口-父类-子类的结构,而接口可以使用父类或者子类实例化,而子类可以复用父类中的方法。这对于Spring 从不同的来源加载配置文件提供了极大的方便

3、给出一个UML图

依据上面讨论的 接口-父类-子类 模型,笔者做了进一步的延伸,就是提供两个接口,并且这两个接口中拥有一个一模一样的抽象方法。

在这里插入图片描述

3.1、提出第一个问题

InterfaceA 和 InterfaceB 中拥有相同的抽象方法 sayHello(),类 FirstClass 需要重写几个 sayHello()方法?

答案是一个。 这意味着,如果我们只是想调用 sayHello()方法,使用InterfaceA 或者 InterfaceB 来进行Spring 注入效果是一样的。

3.2、提出第二个问题

InterfaceA 可否被 Sub1Class 实例化(或者进行Spring注入),FirstClass是否可以被Sub1Class 实例化(或者进行Spring注入)?

答案是:可以;可以。从子类实现接口和子类继承父类来说,这都是Java 继承机制的体现,但是有一点是需要注意的,Spring 默认使用的是 JDK 动态代理,需要借助于接口进行注入,虽然Spring 也支持cglib 动态代理,但是在进行FirstClass 注入Sub1Class时有可能会报无法找到代理类的问题。

3、接口-父类-子类 模型的好处

这种模型的好处在于,当我们新增一个功能的时候可以通过一个新的接口去声明,然后在父类中实现,而子类可以直接调用,但是不需要做额外的工作,对于功能扩展来说对代码的改动是非常友好的。

4、拓展 接口-抽象类-子类

对于复杂业务逻辑,同时存在 批量操作和单个操作的场景,可以使用下面的模型进行扩展。
在这里插入图片描述

4.1、复杂业务可以拆分为多个子逻辑。

从灵活性和简洁性的角度看,分为逻辑与行为的关系,子逻辑行为之间的关系。
逻辑和行为可以拆开。
子逻辑之间的关系可以选择平铺——固定逻辑且逻辑比较简单。也可以借鉴链思维,子逻辑之间分别独立,行为触发下一个子逻辑的调用。

在这里插入图片描述

4.2、批量和单个处理出入参类型不同

可以使用 接口+实现类,或者 接口+抽象类+实现类的方式解决

接口(定义泛型)+实现类(具体类型)
// 接口(定义泛型)
public interface DemoInterface<T,K>{
    K check2(T t);
}
//实现类(具体类型)
public class Demo1Class implements DemoInterface<List,Boolean> {
    public Boolean check2(List list) {
        return null;
    }
}
接口(定义泛型)+抽象类(定义泛型)+实现类(具体类型)
//接口(定义泛型)
public interface DemoInterface<T,K>{
    K check2(T t);
}
//抽象类(定义泛型)
public abstract class DemoAbstract<T,K> implements DemoInterface<T,K> {
    public abstract K check(T t);
}
//实现类(具体类型)
public class Demo1Class implements DemoInterface<List,Boolean> {
    public Boolean check2(List list) {
        return null;
    }
}
5、Jetty 抽象设计参考

将 Http 服务器+servlet容器进行分开抽象和扩展。

第一层:Handler->AbstracHandler
第二层:AbstracHandlerContainer
第三层: HandlerWrapper(过滤器型)、HandlerCollection(协调型-选择为某一个具体的)
第四层: HandlerWrapper子类(内容型)、HandlerCollection子类(内容型)

6、子类覆盖父类的逻辑

抽象父类提供了通用逻辑的写法,子类实现特殊化的逻辑。
但是特殊情况,如果父类提供的基本方法不适用,子类依旧可以覆盖父类的方法——尽管这样会带来一些代码阅读上的障碍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
spring-boot-starter-parent是Spring Boot框架中的一个父项目,它提供了一些默认的依赖管理和配置,用于简化Spring Boot应用的构建和开发过程。每个版本的spring-boot-starter-parent都会随着Spring Boot的发布而更新,以提供最新的特性、修复bug和改进性能。 每个版本的spring-boot-starter-parent可能会有以下方面的差别: 1. Spring Boot版本:每个spring-boot-starter-parent版本都与特定的Spring Boot版本相关联。因此,不同版本的spring-boot-starter-parent会带来不同版本的Spring Boot框架,其中可能包括新的特性、重要的改动或者修复的Bug。 2. 默认依赖版本:spring-boot-starter-parent会预定义一些常用的依赖版本,比如Spring Framework、Spring Data、Hibernate等。每个版本的spring-boot-starter-parent都会更新这些默认依赖的版本,以确保与Spring Boot框架的兼容性和稳定性。 3. 插件配置:spring-boot-starter-parent还会定义一些常用的Maven插件,并配置了一些默认行为。这些插件可以帮助开发人员在构建、测试和部署过程中更加方便地使用Spring Boot。不同版本的spring-boot-starter-parent可能会更新这些插件的版本或者修改默认的配置。 总之,每个版本的spring-boot-starter-parent都旨在提供一个稳定和可靠的基础,以便开发人员可以更加方便地使用和扩展Spring Boot框架。因此,建议在开始一个新的Spring Boot项目时,选择最新版本的spring-boot-starter-parent来获得最佳的开发体验和最新的功能支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值