restful风格

一、什么是 REST ?(一种软件架构风格) 缩写:REST (不是"rest"这个单词) 外文名:Representational State Transfer,简称REST。 中文名:表现层状态转移。 提出时间:2000年。 属性:一种软件架构风格。(以Web为平台的。web服务的架构风格,前后端接口时候用到。) REST之所以晦涩难懂,是因为前面主语(Resource )被去掉了。 全称是: Resource Representational State Transfer。 通俗来讲就是:资源在网络中以某种表现形式进行状态转移。 分解开来讲解: Resource:资源,即数据(这是网络的核心); Representational:某种表现形式,比如用JSON,XML,JPEG等; State Transfer:状态变化。通过HTTP的动词(get查询、post新增、put修改、delete删除)实现。 一句话描述 REST 实质: URL 中只使用名词来定位资源,用 HTTP 协议里的动词(GET、POST、PUT、DELETE)来实现资源的增删改查操作。 什么意思呢? 比如,我们有一个 friends 接口,对于 “朋友” 我们有增删改查四种操作,怎么定义 REST 接口? 增加一个朋友,uri: generalcode.cn/v1/friends 接口类型:POST 删除一个朋友,uri: generalcode.cn/va/friends 接口类型:DELETE(在 http 的 parameter 指定好友 id) 修改一个朋友,uri: generalcode.cn/va/friends 接口类型:PUT(在 http 的 parameter 指定好友 id) 查找一个朋友,uri: generalcode.cn/va/friends 接口类型:GET 上面我们定义的四个接口就是符合 REST 协议的,请注意,这几个接口都没有动词,只有名词 friends,都是通过 Http 请求的接口类型来判断是什么业务操作。 举个反例: generalcode.cn/va/deleteFriends 该接口用来表示删除朋友,这就是不符合REST协议的接口。 不能用deleteFriends ,而应该就用friends + http请求的delete方式。 ...

2024年4月13日 · 1 分钟

模块地狱

个人理解: 有点类似依赖冲突,循环依赖 传递性依赖 遮蔽 版本冲突 复杂的类加载

2023年12月10日 · 1 分钟

关于设计模式

【策略模式】(Strategy Pattern) 其中的Context是一个所谓的“上下文”,不一定非得是个类,也可以只是一个函数/方法。最关键的是,我们其实根本不需要ConcreteStrategyX类,也不需要它们的对象。我们要的只是一个execute函数而已,我们甚至连execute这个函数名都不需要,只要能执行它就行。 看看函数式编程是怎么玩的(这里以大家都熟悉的JavaScript为例): function context(func) { // 做些什么... var result = func() // 有需要的话可以传参 // 再做些什么... } context(function() { // 做些什么... return 123 // 是否需要返回值看需求 }) 一个匿名函数参数func搞定。 Java能搞出这种类图来,全都是因为Java没有一等公民的函数,所以函数必须依附于类(静态方法)或者对象(非静态方法)。而玩静态方法又没法玩多态,而且类不能当成参数传递给其他函数/方法,所以只能用对象携带方法。而对象的方法必须有个名称,为了统一,就叫execute。由于需要多态,所以我们必须提一个接口出来,在接口里声明execute的方法签名。所有这一切说白了都是为了讨好Java编译器,否则它会给你颜色(red)看。 当然,自从Java有了函数式接口和lambda后一定程度上也能玩函数式编程了。 【观察者模式】(Observer Pattern) 这个在JS里大家已经熟悉到不能再熟悉了: someButton.onclick = function(event) { // 处理点击事件 } 又是一个匿名函数搞定!上图里的Subject#attach在这里就是直接赋值。Subject#detach就是赋空值。Subject#notify就是调用一下匿名函数而已。而Observer#update就是匿名函数本身。 【访问者模式】(Visitor Pattern) 能整成这样我也是服了。说白了不就是访问者需要判断一下元素类型嘛。直接套用策略模式,在匿名函数里if-else一下不就行了?(当然还有其他方式,比如引入一个工厂。有模式匹配的函数式编程语言如Haskell、Erlang、Elixir等玩起来更简单)。 【装饰器模式】(Decorator Pattern) 这才是函数式编程的魅力所在! function core1(arg1, arg2) { // 做些啥 return 123 } function core2(arg) { // 做些啥 return 456 } function decorate(core) { // 做些准备工作 return function() { // 做些啥,甚至可以改变参数 var ret = core(...arguments) // 做些啥,甚至可以改变返回值 return ret } } var decorated1 = decorate(core1) var decorated2 = decorate(core2) 酷吧?又是匿名函数搞定!只不过这次的匿名函数是返回值。 ...

2023年10月1日 · 2 分钟

sql中!=的陷阱

mysql/SQL server有,clickhouse也有,hive未验证。 null 值的比较这里另外说下 SQL 里 null 值的比较,任何与 null 值的比较结果,最后都会变成 null,以PostgreSQL为例,如下:select null != null; select null = null; select null > 1; select null <> 1; 以上结果都是 null,而不是什么 true 或者 false。另外有些函数是不支持 null 值作为输入参数的,比如count()或者sum()等。 在写 SQL 条件语句时经常用到 不等于 != 的筛选条件。此时要注意此条件会将字段为 Null 的数据也当做满足不等于的条件而将数据筛选掉。(也就是说会忽略过滤掉为 null 的数据,导致数据不准确)。 SELECT * FROM A WHERE B1 != 1 不会查出null值 修改: SELECT * FROM A WHERE B1 != 1 OR B1 is Null SELECT * FROM A WHERE IFNULL(B1,'') != 1 为什么会这样呢?这还得从 mysql 的底层开始说起,因为 NULL 不是一个「值」,而是「没有值」。 「没有值」不满足「值不等于1」这个条件,怎么解决可以使用 ifnull() 方法,将 null 转为空字符串,或者这个字段做出判断 加上OR a is null。当然使用 ifnull 相率会更好 select null = null返回也是null。null只能用is或is not

2023年8月6日 · 1 分钟

left join 谓词下推

zzz1 uid is_delete 1 1 2 0 3 0 zzz2 uid is_delete 1 0 2 1 3 0 select * from zzz1 left join zzz2 on zzz1.uid = zzz2.uid where zzz1.is_delete = 0 and zzz2.is_delete = 0 结果: 3 0 3 0 select * from (select * from zzz1 where zzz1.is_delete = 0) z1 left join (select * from zzz2 where zzz2.is_delete = 0) z2 on z1.uid = z2.uid 结果: 2 0 NULL NULL 3 0 3 0 select * from (select * from zzz1 where zzz1.is_delete = 0) z1 left join (select * from zzz2 where zzz2.is_delete = 0) z2 on z1.uid = z2.uid where z2.uid is not null 结果: 3 0 3 0 ...

2023年2月19日 · 1 分钟

kafka在zk中的目录结构

2023年1月22日 · 0 分钟

Kafka 中的控制器组件

控制器组件(Controller),是 Apache Kafka 的核心组件。它的主要作用是在 Apache ZooKeeper 的帮助下管理和协调整个 Kafka 集群。集群中任意一台 Broker 都能充当控制器的角色,但是,在运行过程中,只能有一个 Broker 成为控制器,行使其管理和协调的职责。换句话说,每个正常运转的 Kafka 集群,在任意时刻都有且只有一个控制器。官网上有个名为 activeController 的 JMX 指标,可以帮助我们实时监控控制器的存活状态。这个 JMX 指标非常关键,你在实际运维操作过程中,一定要实时查看这个指标的值。下面,我们就来详细说说控制器的原理和内部运行机制。 在开始之前,我先简单介绍一下 Apache ZooKeeper 框架。要知道,控制器是重度依赖 ZooKeeper 的,因此,我们有必要花一些时间学习下 ZooKeeper 是做什么的。 Apache ZooKeeper 是一个提供高可靠性的分布式协调服务框架。它使用的数据模型类似于文件系统的树形结构,根目录也是以 “/” 开始。该结构上的每个节点被称为 znode,用来保存一些元数据协调信息。 如果以 znode 持久性来划分,znode 可分为持久性 znode 和临时 znode。持久性 znode 不会因为 ZooKeeper 集群重启而消失,==而临时 znode 则与创建该 znode 的 ZooKeeper 会话绑定,一旦会话结束,该节点会被自动删除==。 ==ZooKeeper 赋予客户端监控 znode 变更的能力,即所谓的 Watch 通知功能。一旦 znode 节点被创建、删除,子节点数量发生变化,抑或是 znode 所存的数据本身变更,ZooKeeper 会通过节点变更监听器 (ChangeHandler) 的方式显式通知客户端。== 依托于这些功能,ZooKeeper 常被用来实现集群成员管理、分布式锁、领导者选举等功能。==Kafka 控制器大量使用 Watch 功能实现对集群的协调管理==。我们一起来看一张图片,它展示的是 Kafka 在 ZooKeeper 中创建的 znode 分布。你不用了解每个 znode 的作用,但你可以大致体会下 Kafka 对 ZooKeeper 的依赖。 ...

2022年12月25日 · 2 分钟

flume动态加载配置原理

Flume NG支持运行时动态修改配置的配置模块 细说一下PollingPropertiesFileConfigurationProvider提供的运行时动态修改配置并生效的能力。 要实现动态修改配置文件并生效,主要有两个待实现的功能 观察配置文件是否修改 如果修改,将修改的内容通知给观察者 对于第一点,监控配置文件是否修改,Flume NG定义了一个FileWatcherRunnable对象来监控配置文件,启动了一个单独的线程采用定时轮询的方式来监控,轮询频率是30毫秒一次,比较file.lastModified属性与lastChange时间戳,当file.lastModified > lastChange时表示文件被修改 public class FileWatcherRunnable implements Runnable { private final File file; private final CounterGroup counterGroup; private long lastChange; public FileWatcherRunnable(File file, CounterGroup counterGroup) { super(); this.file = file; this.counterGroup = counterGroup; this.lastChange = 0L; } @Override public void run() { LOGGER.debug("Checking file:{} for changes", file); counterGroup.incrementAndGet("file.checks"); long lastModified = file.lastModified(); if (lastModified > lastChange) { LOGGER.info("Reloading configuration file:{}", file); counterGroup.incrementAndGet("file.loads"); lastChange = lastModified; try { eventBus.post(getConfiguration()); } catch (Exception e) { LOGGER.error("Failed to load configuration data. Exception follows.", e); } catch (NoClassDefFoundError e) { LOGGER.error("Failed to start agent because dependencies were not " + "found in classpath. Error follows.", e); } catch (Throwable t) { // caught because the caller does not handle or log Throwables LOGGER.error("Unhandled error", t); } } } } // PollingPropertiesFileConfigurationProvider.start()启动一个单独的线程来监控properties配置文件 public void start() { LOGGER.info("Configuration provider starting"); Preconditions.checkState(file != null, "The parameter file must not be null"); executorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryBuilder().setNameFormat("conf-file-poller-%d") .build()); FileWatcherRunnable fileWatcherRunnable = new FileWatcherRunnable(file, counterGroup); executorService.scheduleWithFixedDelay(fileWatcherRunnable, 0, interval, TimeUnit.SECONDS); lifecycleState = LifecycleState.START; LOGGER.debug("Configuration provider started"); } 对于第二点,利用Guava EventBus提供的发布订阅模式机制,将配置修改封装成事件传递给Application,来重新加载配置 ...

2022年6月12日 · 2 分钟