前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >回 Yong9981 关于 Act-1.8.32 发布新闻中的评论

回 Yong9981 关于 Act-1.8.32 发布新闻中的评论

作者头像
老码农
发布2020-03-12 10:38:28
5320
发布2020-03-12 10:38:28
举报
文章被收录于专栏:老码农专栏老码农专栏

@yong9981actframework-1.8.32 发布新闻 中提出了一下问题:

我的回应是:

然后 yong 同学非常热心的贴了下面这段评论:

这里面我用红色标注出两段有趣的论点:

你提供的功能和SpringBoot/JBoot有很多重叠的部分

这个有问题吗? 还是不应该重复发明轮子?

SpringBoot的基本原理是用一个通用的IOC(AOP)工具配置一堆第三方工具,这些第三方工具原本和SpringBoot没有一毛钱关系,只是因为它们的优秀被Spring看中整合进来,你的竟争对手是这么个集成体系,而且它随时可以添加新的模块进来,因为本质上通用IOC工具的作用就是用来初始化Bean的。它们有个共同的特点:没有源码,所以比较适合用YML/XML或Java方式配置,而不是用JSR330注入。

这段话里面包含下面几段陈述:

  1. SpringBoot 就是一个通用 IOC 工具 - 如果你的 SpringBoot 包含了 SpringFramework, 嗯, 我部分认同这个观点.
  2. Spring 三方工具的共同特点: 没有源码 - 真的吗? @yong9981 同学? 请问你有没有去 https://github.com/spring-projects 看看里面的三方插件有没有源码?
  3. Spring 三方工具比较适合用 YML/XML 或者 Java 方式配置 - 您的 point 在哪里? Act 和 Act 的插件都使用 properties + Java 方式配置, 不行吗?
  4. Spring 三方工具不适用 JSR 330 注入 - Spring 开始自己的 DI 框架的时候 JSR330 还不存在, 因此 Spring 自成体系, 可是还是那句话, 您在这里到底想表达什么意思?

至于 yong 同学在上面说的建议, 我的建议是:

接下来 yong 同学讲到:

类Guice的配置不如Spring配置通用和方便

类 Guice 配置是 Java 的标准, 不如 Spring 配置通用是现状, 不如 Spring 配置方便我不认同.

需要开发插件往往是要用AOP功能的,如果不需要AOP,直接new就行了。比方说spring-data-mongodb也实现了AOP联盟标准,所以Guice也可以拿来用的,但你看Genie能不能拿来用?这是个架构问题,导致所有spring插件你都必须重新开发一个,偷懒都偷不了

@yong9981 这是我最后一次就 IOC 和 AOP 的问题回答你, 我们以前已经就此问题讨论多次: 2019-11-30 的讨论, 2019-12-25 的讨论, 2019-12-26 的讨论

  1. 我第一次接触 AOP 大概在 2001 年, 一篇讲 LoD (Law of Demeter) 的文章将我带到了 aspectj 的项目网页, 当时 aspectj 还是 Xerox Palo Alto 实验室的内部项目, AOP 联盟还不知道在什么地方. 我一开始也为 AOP 感到兴奋, 认定这是对 OOP 之后的一次革新. 在随后的几年中, 我一直关注 AOP 的发展. 当 aop 创始人自己开始和一个微软的大佬搞新的 intentional programming, 我又开始追这颗新星, 但一直到现在 intentional programming 也没有任何实际的东西出来. 我讲这些的目的是为了告诉你, 我理解 AOP, 也知道这是干什么用到, 我第一次尝试 aspectj weaver 的时候可能比你接触 AOP 还要早. 所以请你不要再用你 充满误解 的思想给我推销 AOP. 当我有时间和动机为 Act 提供 AOP 支持的时候我会去做, 但绝对不是在 Genie 里面. 我对 DI/IoC/AOP 这些概念有非常清楚的认识, 而且我相信这些认识和业界对这些概念的公识是一致的. 顺便劝告你一句, 到维基百科或者其他权威站点温习一下这三个概念.
  2. 更重要的不要再用支持了 AOP 就支持了 Spring 生态中的三方插件这种很二的观点来推销 AOP. 我已经讲过多次, Java 各个生态之间不会因为支持 AOP 或者其他任何规范就能够相互共享三方插件. 也许就像你给出的例子, 可能会有人出于学习或者技术展示目的搞出类似 https://github.com/mohitsinha/play-java-spring-data-mongodb 这样的项目, 我想说实际情况是生态之间并不共享插件. 另一方面生态之间共享规范, 也共享一些工具库, 比如 Hibernate, MyBatis 之类的, 但要将工具库集成进真正的生态, 必须提供插件, Spring 这样做, Play 这样做, Act 也这样做. 没有人因为支持 AOP 就可以原封不动的使用另一个生态的插件. 即便是上面那个 play-java-spring-data-mongodb 这样的 demo 项目, 也需要花费数百行代码, 而不是像你说的"共同的特点:没有源码". 你在回复中举的另一个例子 http://kasparov.skife.org/blog/src/java/guice-with-spring-transactions.html 是很辛苦寻找出来的吧, 一篇 2007 年的 blog, 有任何实际价值吗? 还是就像博主说的:

最后来看看你的项目:

那个 Guice/jBeanBox 实现 Spring 声明式自动回滚事务的就不多说了, Genie 没有实现 AOP, 所以我做不了. 但放在一个更大的 Context 下, Act-Db 是可以做自动事务回滚的, 这是不同的生态. 再次强调, 别让我去支持 Spring 机制, 我不会容忍在 Act 代码里面引入一大堆 Spring jar 文件这样的事情 更别让我因为要支持 Spring 机制, 所以在 Genie 中实现 AOP!

你项目这个 Question 倒可以谈谈:

我第一眼看这个代码就想问: 干嘛要先搞个

代码语言:javascript
复制
	public static class CarConfig extends BeanBox {
		{
			this.injectConstruct(car, String.class, color);
		}
	}

然后

代码语言:javascript
复制
Car car = JBEANBOX.getBean(CarConfig.class);

直接

代码语言:javascript
复制
Car car = new Car1(color);

它不香吗?

yong9981 大概要说, 没看见我的 colorcar 都标注有 "// read from file" 吗?

那我的回答是, 有多么蠢的项目才会这样来配置?

直接在配置文件里面给出实现类的情况有没有? 当然有, 比如你的数据库插件可能是 Hibernate 的, 也可能是 MongoDB 的, 所以会在配置文件中指定数据库插件实现类. 另一个例子, 假设你使用 osgl-storage 来存放上传文件, 你会在配置文件中指定存储系统是本地文件系统, 还是七牛云, 或者 Azure Blog, 这种情况, 也需要直接在配置中给出存储服务的实现类. 然而这些情况的共同特点是都是 Heavy load, 需要的配置和初始化, 绝不仅仅用一个构造函数就搞定的. 为应用完成重型对象配置和初始化工作正是插件的价值.

那 DI 注入本身有没有价值呢? 当然有, 假设你有两个数据库服务配置:

代码语言:javascript
复制
db.instances=sales,marketing

db.sales.implementation=org...HibernateService
db.sales.url=<jdbc-url to sales db>

db.marketing.implemenation=org...MorphiaService
db.marketing.url=<jdbc-url to  marketing db>

DI 的威力就在于代码可以清晰地指定需求而无需考虑如何准备这个需求, 例如:

代码语言:javascript
复制
public class XyzService {
	@Named("sales")
	@Inject
	private DataSource salesDs;
	
	@Named("marketing")
	@Inject
	private DataSource marketingDs;
}

当然我注意到 yong9981 在代码中演示的特性是 "使用外部工具时,比如说A中要注入B属性,B的构造器要注入C对象这种, 而且A,B,C全是第三方工具,拿不到源码,所以不能使用注解方式去配置。". 我觉得这里面需要考虑的一个问题是 这种没有考虑依赖注入的代码是否值得 DI 工具去适配, 或者需要适配到何种地步

jBeanbox 的 API 提供了一种比较粗糙的 API 包装来强行适配这种场景 (估计实际案例中很少会出现吧):

其中全然没有考虑一点类型安全, 在其演示代码中, 做一点改变, 让 Car1 不再继承 Car, 即下面代码中的 car 不再是 Car 的实例:

在编译时没有办法检测到这样的问题. 知道运行时才会在这里抛出错误:

这样的代码貌似简洁 (其实在所有已知条件下, 反而不如直接用 new 操作符), 但把 Java 这种类型安全语言当做动态语言来使用, 实际项目上怕是有点隐隐担忧吧.

从我看来, DI 工具为所谓三方库提供这样的适配是得不偿失的. 那 Genie 能否处理 Contructor binding 呢, 当然是可以的. 下面是 Genie 的实现代码:

这里我们看到了几个地方的不同, 首先将 Car.class 绑定到 Car1.class 的过程是类型安全的. 我们把 Car1 改写, 让其不要继承 Car, 我们发现 IDE 会有错误提示:

其次, 我们并没有直接向构造函数绑定中去写某个具体的值 e.g "red", 而是通过 @Named 注解来告诉 DI 引擎, 当你遇到名字为 color 的字串的时候, 提供 red 这个值. 这样的做法看起来有这样的问题, 如果你的构造函数参数上面没有 @Named 注解, 那就没法绑定到需要的值了. 在此我想强调的是依赖注入处理的应用程序逻辑拓扑, 并不是数据. 每个注入的对象都应该是一个特定概念, 构造函数绑定也不应该脱离这个观念. 因此你注入的对象要不应当是一个特定类型, 要不是普通数据类型假设某个 Qualifier (比如 @Named) 来限定这个概念范围.

设想你有下面的构造函数:

代码语言:javascript
复制
public class MyAwsS3ServiceAgent {
    private String awsKey;
	private String awsSecret;
	public MyService(@Named("aws.key") awsKey, @Named("aws.Secret") awsSecret) {
		this.awsKey = awsKey;
		this.awsSecret = awsSecret;
	}
}

在构造函数中清楚地地指定了参数的概念, 因此我们可以让 DI 引擎发现其中的逻辑关系并提供需要的值绑定. 看官可能要问, 如果我用的是很老的库, 的确没有 @Named 这样的机制怎么办. 我的回答是应用提供一层 Wrapper 来封装这个库, 适配到 DI 引擎. 这种做法的优势在于所有的概念都很清晰, 所有的值来源也很透明. 代码的可维护性和采用 jBeanBox.injectConstruct 这样晦涩不清的 API 相比不可同日而语.

另一方面, yong9981 的代码除了有两句注释说明 car 和 color 的值来自配置文件, 但其实根本没有演示如何把配置从文件加载进 JVM 的. 下面的代码演示 Genie 是如何处理这个过程的.

为了更好地展示 Genie 这方面的能力, 我们在 Car 中添加一个整型字段: seats (座位数):

我们在 test/resources/test.properties 文件中准备好配置数据:

然后我们需要适配 Genie 提供的 ConfigurationLoader 机制到这个配置文件中:

注意上面的适配机制每个应用只需要完成一次即可. 下面是绑定和测试代码:

注意到 Genie 的配置机制很聪明地将配置文件中的 "6" 变成需要的整型变量 6 了吗? ActFramework 中大量使用了这样的机制. 大家可以参考一下这个演示项目

总结一下: 提供工具库, 比如 Genie 这样的 DI 引擎, 我们应该仔细思索提供这个工具的目的是什么, DI 的目的到底是什么, 在什么层面上可以帮助应用程序, 使用这个工具是否有利于应用程序的代码组织, 维护, 是否鼓励更好的编码方式. 毫无选择地提供粗糙的封装 API 只能让工具沦为没有价值的玩具

最后, 文中的代码都在 https://gitee.com/greenlaw110/GuiceSpringTx 项目中, 有兴趣的朋友可以 Checkout 出来看看

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档