首页 > 其他分享 >从Spring中学到的【2】--容器类

从Spring中学到的【2】--容器类

时间:2022-12-29 19:12:28浏览次数:50  
标签:容器 source -- Spring 可以 对象 public

容器类

我们在实际编码中,常常会遇到各种容器类,他们有时叫做POJO,有时又叫做DTO,VO, DO等,这些类只具有容器的作用,具有完全的get,set方法,作为信息载体,作数据传输用。

其实,很多地方都可以看做将对象看做容器。比如,一些起到标签作用的接口,Serializable, **Aware接口等;注解元信息,比如@Order提供排序信息,@Value提供值注入,@Autowired提供属性注入等。

这种容器类一般很少具有面向对象的方法,又叫做贫血模型。与之对应的是充血模型,适合用于复杂系统,Spring源码显然就是充血模型占绝大多数,基于了面向对象的思想:对象=数据+行为。但是Spring中也经常见到许多容器类,有些类的一部分也可以看做容器。

函数式模型

函数式编程思想下,一个对象通常值为不变的。这样做的好处有很多,仅列举一些:便于支持并发,是线程安全的;对象是无状态的,极大地简化代码的理解,因为每一次值的变化都是显性的;便于编译器优化性能,比如延迟计算,实现对象复用;便于测试,因为没有副作用,每一次执行方法返回的结果都唯一。

这种对象称为值对象,Lombok中使用@Value标注,JDK14开始引入的record关键字实现了相同功能。比如Map容器对Key的要求就是值对象。以后有时间我再写一下函数式的一些基本思想。

举例1:MVC模型

MVC模型中,Model, View, Controller中我们使用的数据传输对象一般就使用POJO。一般情况下,一个请求过来,SpringMvc 可以将Json格式的字符串反序列化为POJO,一般为**Request。进行一系列计算或数据库交互后,返回可序列化的POJO对象,SpringMvc 将其序列化为Json。

举例2:各种配置的属性

我们经常使用的@Value、@ConfigurationProperties注解可以快速配置对象的属性,配合@RefreshScope可以实现动态刷新配置。

@Value注解的中的值还支持EL表达式,供我们灵活取用。

举例3:Spring 事件

观察者设计模式中的事件都是值对象。一个事件可以被多个listener监听,如果有一个listener改变了事件的某些属性,其他listener无法确定事件是否被更改过,系统运行的结果就不稳定。

我们简单地看下refresh模板方法,在容器刷下完毕之后,会调用finishRefresh方法,这个方法会发布事件ContextRefreshedEvent。我们看一下ContextRefreshedEvent的源码就会发现,其值只在构造器创建对象时确定,不包含set方法。

public class ContextRefreshedEvent extends ApplicationContextEvent {
	public ContextRefreshedEvent(ApplicationContext source) {
		super(source);
	}
}

public abstract class ApplicationContextEvent extends ApplicationEvent {
	public ApplicationContextEvent(ApplicationContext source) {
		super(source);
	}
	public final ApplicationContext getApplicationContext() {
		return (ApplicationContext) getSource();
	}
}
public abstract class ApplicationEvent extends EventObject {
	private static final long serialVersionUID = 7099057708183571937L;
	private final long timestamp;
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}
	public final long getTimestamp() {
		return this.timestamp;
	}
}

public class EventObject implements java.io.Serializable {
    private static final long serialVersionUID = 5516075349620653480L;
    protected transient Object  source;
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }
    public Object getSource() {
        return source;
    }
    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

也可以用IDEA提供的Structure功能看,一目了然。
image

打断点到对应位置
image

模板方法refresh
image

举例4:Monad

前置知识:我们知道Java Stream支持以下操作:filter, map, flatMap, collect, reduce。以上这些操作就是我们经常使用的,入参通常为函数。

monad是一个很复杂的概念,也很难解释。我们可以从使用的角度来简化理解,其就是一个容器,这个容器包装了其他的对象,这个容器包装了对象的行为,可以使用map、flatMap等方法。

不严格地说,如果没有Null,Optional就是一个Monad,数据库查询的返回值应该是Optional

java8 引入Stream流后,集合类型也可以看做Monad,比如members.stream().filter(validPredicate).map(Member::getSalary).mapToInt(x → x).sum()

monad中的 flatMap 可以避免套娃。

在Java中常见的套娃就是Try Catch,使用vavr库中的Try可以解决,Try.of(逻辑1).faltMap(逻辑2),代码运行后,Try包装的对象要么是正常业务执行的返回值,要么是遇到的Exception。

比如我想查询数据库,查询公司职员A的主管。

member = repo.getByName(a);

manager = member.map(Member::getManager).flatMap(repo::getByName);

总结

  1. 阅读源码的过程中,我们更应该关注的是类的行为,或者说是对于数据的处理。而对于数据类的存放位置,可以放在次要的位置。
  2. 数据的表示可以是POJO类、值类型、数组、基本数据类型以及他们之间的组合,我们在编码过程中更应该注意其结构的可读性和是否选取 Immutable(不变)来表示。
  3. 关注数据的传递,可以说数据的传递表达了系统的架构。有时候虽然我们并不知道数据的传递过程,但是我们更在意数据传递的结果。

关于第 3 点举一个例子,使用@Order 注解可以为一组类进行排序,再阅读源码之前,我们虽然不知道是哪个具体的类去处理的,但是其处理的过程必然包括了以下过程:获取注解值,对原有类与排序号进行关联,一个通用的排序方法排序。

SpringBoot自动配置了许多类,我们虽然不知道具体的配置是如何映射到我们在容器中使用的Bean,但是可以确定数据的传递必然经历了 配置 → 解析 → 注册Bean的过程。从实用的角度出发,多数情况下,我们不必知道一个Bean的创建的具体逻辑,我们只是拿来就用,按需配置,我们需要了解的是这个Bean可以做什么。

事实上,Spring项目中,除了少数的方法类(比如各种**Strategy),随便拿出一个类,基本都可以看做容器类,后续我会结合一些代码再进行详细分析,敬请关注。

标签:容器,source,--,Spring,可以,对象,public
From: https://www.cnblogs.com/dahua-dijkstra/p/17013286.html

相关文章

  • SketchUp学习笔记
    SketchUp学习笔记常用命令: 视口平移:按住shift键+按下鼠标滚轮进行拖动或者H键视口旋转:按下鼠标滚轮键视口缩放:转动鼠标滚轮空格键选择工具......
  • rman配置详细
    可以通过SHALLALL命令查看RMAN的配置信息RMAN>showall;RMAN配置参数为:CONFIGURERETENTIONPOLICYTOREDUNDANCY1;#default CONFIGUREBACKUPOPTIMIZATIONOFF......
  • Kubernetes(k8s) kubectl auth常用命令
    kubectl在$HOME/.kube目录中查找一个名为config的配置文件。可以通过设置KUBECONFIG环境变量或设置--kubeconfig参数来指定其它kubeconfig文件。本文主要介绍K......
  • 监控flash_recovery_area的使用情况
    监控flash_recovery_area的使用情况可以查询2个视图:1.V$FLASH_RECOVERY_AREA_USAGE:displaysusageinformationaboutflashbackrecoveryareas SQL >   select......
  • dremio 参考配置参考
    实际上我以前简单说明过,下边包含一个官方文档完整的,方便参数学习官方提供的参考配置dremio-reference.confincludeclasspath("dremio-reference-ext.conf")......
  • Form
    编译formcd$AU_TOP/forms/ZHS#12.xfrmcmp_batchModule=$CGL_TOP/forms/ZHS/CUXWOIPWOI.fmbUserid=apps/appsModule_Type=FORMoutput_file=$CGL_TOP/forms/ZHS......
  • dremio jdbc 客户端简单说明
    dremiojdbc客户端实际上包含了基本上两大类,一个是传统jdbc的,一个是基于apachearrowflightsqljdbc的当前主要说明传统jdbc客户端的,内部上dremio基于了calcite......
  • 不止稳定快速,看华为云CDN如何在国际云服务市场中“分蛋糕”
    互联网时代,网络的应用已十分普及,但依然存在下载慢、网络卡顿的现象。如企业业务运行过程中出现的卡顿现象导致数据延时;各校因疫情等原因网课时间长、访问应用人数过多,造成网......
  • 不止于快,华为云CDN加速服务对OBS桶文件加速的超实用技巧
    随着企业数据上云的热潮愈演愈烈,不少企业开始将图片、视频、软件包等静态资源文件数据存储在OBS桶内,并将OBS桶作为网站、论坛、APP、游戏等业务的存储源。当企业用户需要获......
  • 华为云CDN加速,如何助力企业更好发展?
    随着当下互联网技术高速发展,人们可以通过网络来浏览各式各样的内容,但当遇到访问人数过多等情况时,便会使服务器出现负载过重的问题,进而影响用户在访问过程中的上网体验,这对网......