最近注意到一个很有意思的项目 Diagrams, 用 Python 代码来绘制架构或流程图, 以前基本用 Gliffy 来画。继一系列 X as X, 如 PaaS, SaaS, IaaS, CaC(Configuration as Code), IaC(Infrastructure as Code) 等,Diagrams 喊出了 Diagram as Code 的口号。其实,在这之前, Markdown 就做了许多 Diagram as Code 的事情, 也许更准确说是 Diagram as Document。
熟练的程序员大概不喜欢用可视化设计器来生成 GUI 代码,那会让代码变得极不简洁,而是直接写,眼中看到的是代码,头脑中即时产生映像。
Diagrams 就是这样一款写 Python 代码产生架构或流程图的库,它绘制的架构图支持主要的云服务提供商,如- 知名的(本人认为的): AWS, Azure, GCP, IBM, DigitalOcean, AlibabaCloud, OCI(Oracle Cloud Infrastructure, 不是 Open Container Initiative), OpenStack
- 刚了解到的: Google 的 Firebase, Elastic(ElasticSearch 出品方也有自己的平台), Outscale
- 以及应用平台 K8S, Saas 和 OnPrem 中的元素
- 通用元素,编程语言及流程图,还能定制自己的节点图
Airflow 起初是由 Airbnb 开发的, 用于调度和监控工作流的平台,后来开源了, 并于 2019 年 1 月成为了 Apache 的顶级项目。它是用 Python 编写的,管理的工作流是有向无环图(DAG - Directed Acyclic Graph), 这能满足绝大多数情况下的需求。
顺带插一句,Airflow 用了与 Google Photos 极其相似的 Logo,不知算不算侵权。
说到工作调度,头脑中很快会掠过 Cron, 计划任务, Quartz, Spring Schedule, 和 Control-M。除了商业的 Control-M 有调度和监控工作流的功能外,其他的基本只用来调度任务,监控全靠自己的日志。
还有一个类似的工具是由易观贡献给 Apache 的 DolphinScheduler, 它处理的也是 DAG 工作流,用 Java 实现的,所以体量大,硬件要求会高些。它的工作流的创建是通过 Web UI 可视化界面完成的,对程序员来说不那么友好。奇怪的是, 作为 Apache 旗下的项目,项目首页面是中文的,启动后控制台默认界面也是中文的。
而 Airflow 功能就厉害了, 它可动态管理工作流,易于扩展,可集群化进行伸缩,更有一个漂亮的 UI 用于实时监控任务。基于以上特性 Airflow 是很适于执行数据的 ETL(Extract, Transform, Load) 操作的。
这么好的开源产品, 免不了又被 AWS 盯上了, 以 Amazon Managed Workflows for Apache Airflow(MWAA) 服务进行出售,费用还真不菲。AWS 创造性的以 vCPU 数量,DAG 数量限制进行分层次进行收费,远比自己启动一两个 EC2 实例部署 Airflow 贵的多。但 MWAA 有个方便的特性就是 DAG 文件可以放到 S3 中自动部署,相信自己部署的 Airflow 也能进行扩展而从 S3 加载 DAG。 Read More
要在一个 Spring 应用中开启缓存方法返回结果的功能很简单,不需要额外的依赖,相关的的注解 @Cacheable, @CacheConfig, @CachePut, @CacheEvict, @EnableCache 等来自 spring-context 包。默认的的 Cache 实现是把数据存入到 ConcurrentMap 中,所以数据一直在内存中,除非显式的调用被 @CacheEvict 的方法来清理。实际进行数据缓存时会有更复杂的策略,如元素个数,占用内存,过期时间,何时使用磁盘等,而且不同的数据类型应有不同的缓存策略。
因此,除了使用默认的 ConcurrentMap 作为缓存外,还可通过配置属性spring.cache.type来使用其他类型的缓存,如 Caffeine, Couchbase, EhCache, INfinispan, JCache, Redis 等,或自定义 CacheManager 来使用 Guava Cache。 Read More
在 Spring Web Controller 方法中的参数可用 org.springframework.web.bind.annotation 下的各种注解来说明参数值从哪儿获得,比如我们熟知的 @PathVariable, @RequestParam, @RequestHeader, @RequestBody, 还有较少使用的 @ReqeustAttribute, @SessionAttribute, @RequestPart, @MatrixVariable, @ModelAttribute, @AuthenticationPrincipal, @CurrentSecurityContext 等。其实在它们背后工作的是相应的 HandlerMethodArgumentResolver 的子孙们,当然还有 HttpMessageConverter 的各个实现类还默默的对输入数据进入类型转换。
为进一步深入了解 Spring Web 如何获得用户输入,我们先尝试一下不常用的注解,然后实现一个自己的注解参数 @ProductId, 它来从 queryString 或 requestHeader 中获得 productId。写作本文的起因是在上一篇 理解 Spring Boot Security + JWT Token 的简单应用 里, JwtTokenFilter 住 SecurityContextFilter 放一个 Authentication 实例, 在 Controller 方法中便能用 @AuthenticationPrincipal 自动注入 authentication.getPrincipal() 的值。 Read More
项目中有用到 Spring Security 来控制 API 的访问权限,但对于配置应用它基本上是照葫芦画瓢。至于为什么要调用方法SecurityContextHolder.getContext().setAuthentication()
并且能从 HttpServletRequest 中得到 Authentication。还有,只要在 Controller 的方法中添加一个带 @AuthenticationPrincipal 注解的参数public String sampleApi(@AuthenticationPrincipal DecodedJWT decodedJWT) {...}
之后,decodedJWT 便自动有了值,诸如此类的,此前一概模糊不清。
早先配置 spring-security-config 是通过继承 WebSecurityConfigurerAdapter, 覆盖它的 configure(HttpSecurity http) 来配置访问规则等。在 spring-security-config 5.7.x 开始不建议用 WebSecurityConfigurerAdapter, 而是借由 SecurityFilterChain 来配置 HttpSecurity 中的规则 ,或者通过 WebSecurityCustomizer 完成定制。 Read More
还是很 久很久以前,当初有 Java 调用本地动态库需求的时候,尝试过用 javah/native 原生的方式在 Java 中使用动态库,再就是小试了 JNative,它调用动态库只需 Java 端的动作, 它最后的更新日期是 9 年前 2013-04-26,基本是应该选择放弃了。
关于 JNative 的使用写过两篇
如今想继续发掘下是否有别的更好的调用本地库的 JNI 组件,找到有- JNIWrapper:居然是一个收费的,而且价格不菲,不作绍
- BridJ:也是 7 年前才有过代码的更新
- JNA(Java Native Access): 也就它稍为活跃一点点
- JNR-FFI:最近几个月也有更新,不知道使用体验如何
Read More
Python 3.10 于 2021-10-04 发布,至今已大半年,目前 AWS 的 Lambda 尚未直接支持,但用 Docker 镜像的方式使用 AWS Lambda 是可以使用 Python 3.10。Python 一年一发布的节奏比 Java LTS 还紧密。下一个版本 Python 3.11 预计在 2022-10-03 发布。在学习 Python 3.10 之前先回顾一下 Python 3.7, 3.8, 3.9 的特性(不想关心之前版本的变迁可直接跳跃到下方的 Python 3.10 新特性去)
Python 3.7 所带来的新特性- breakpoint()
- 数据类(@dataclass)
- 类型提示强化和延迟注解求值
- 时间精度的提高
- 保证字典的顺序
- async 和 await 成为关键字
- asyncio.run() 简化事件循环
- 上下文变量(ContextVar) - 可实现 ThreadLocal 和 SLF4J 的 MDC 功能
- 在学习 Python 3.10 新特性时,其中有个类型别名(TypeAlias), 所举的例子是
1StrCache = 'Cache[str]' # a type alias<br /> 2LOG_PREFIX = 'LOG[DEBUG]' # a module constant
可写成1StrCache: TypeAlias = 'Cache[str]' # a type alias<br /> 2LOG_PREFIX = 'LOG[DEBUG]' # a module constant
这让 StrCache 更像是一个类型别名,而不是一个看起来明显就是Cache[str]的字符串变量(实际上它确实是)。
本文不在 TypeAlias 本身,而是从Cache[str]能看出 Python 似乎也能支持像 Java 那样的泛型, 就像 Python 内置支持的 List[str] 或 list[str] 那样。
那么来看 Python 怎么去实现一个只能放入字符串的Cache[str]Cache, 而不能放入别的类型。 Read More
Python 不支持函数重载,在同一个模块中声明同名方法不会报错,只会不停的覆盖,无论参数个数是否不同,最终只会保留最后一个函数1foo = 100 2 3def foo(a): 4 print('foo(a)') 5 6def foo(a, b): 7 print('foo(a, b)') 8 9def foo(a: str): 10 print('foo(a: str)') 11 12foo([8]) 13print(globals()['foo']) 14foo(3, 5)
输出 Read More
Python 3.10 虽已于 2021/10/04 发布,但目前主要使用的 Python 版本仍然是 3.9。之前有两篇介绍了 Python 3.7 和 3.8 带来的新特性
于此,再补充一下 Python 3.7 和 3.8 各自的发布日期是 2018/06/27 和 2019/10/14。Python 3.9 是在 2020/10/05 发布,由此看出 Python 是每年一发布。
每个版本的主要新特性就是它们的亮点,不关注新特性也就不能很好的掌握这种语言,除非是直接使用汇编或字节码指令,他们的变迁比较缓慢。
对于以 Python 3.9 为现阶段基准版本使用来说,更有必要了解一下 Python 3.9 的新特性,不然别人一见代码就仿佛是以二战时的打法应对现代战争。
Python 3.9 主要有哪些新特征呢?总结起来就是
字典的更新/合并, 字符串新增删除前/后缀的方法,datetime 支持时区了, Executor.shutdown() 可取消未执行的任务,类型提示可直接用 list[str], dict[str, int] 这样表示泛型 Read More