文档章节

谈谈 Act 的依赖注入 和 模板输出 - 回 drinkjava 同学的评论

罗格林
 罗格林
发布于 11/30 18:15
字数 4038
阅读 1182
收藏 14

1. 背景

依赖注入工具 jBeanBox 的作者 drinkjava 同学最近在 gitee 上对 Actframework 项目 提出了如下评论:

首先感谢 drinkjava 同学的意见, 看得出来是问题是认真思考之后提出来的. 本文将就评论中的两段意见分别作答. 在此之前先解释一下上面那段评论中的术语:

  • DI - Dependency Injection - 依赖注入, 反向控制的一个特例, 指在构造对象时对象的(某些)状态不由对象类自身逻辑初始化,由 DI 框架依照环境配置以及状态上的申明注入.
  • AOP - Aspect Oriented Programming - 面向切面编程, 允许使用特定技术将逻辑编织进程序结构中, 逻辑对应程序结构中特定的切点.

2. [意见一] 一个 MVC 工具为什么要引入 DI 依赖注入

你这个DI工具的出发点可能有问题,一个MVC工具为什么要引入DI依赖注入?

这个问题有两个地方值得商榷:

  1. 上面这个问题隐含的一个前提假设是 Act 是一个 MVC 工具. 实际上这个前提有一点问题, 我启动 Act 项目的动机是希望弄一个符合自己想法的 PlayFramework V1.x 的后继者. Play 本身除了是一个开发框架,也是一个运行时平台, Act 也是. 单单用 "MVC 工具" 来描述 Act 并不符合我自己的想法. 用 "MVC 工具" 来描述 Act 的依赖 osgl-mvc 更能够贴切一点.

  2. MVC 工具为什么不能引入 DI 依赖注入. 后面 drinkjava 同学也提到 "直接引入 Spring 或 Guice 的不好吗?", 说明 drinkjava 并不是认为 MVC 工具不能引入 DI 依赖注入, 而是认为 Act 引入的 DI 依赖注入 Genie 没有提供 AOP 功能, 而 AOP 功能在他看来是实现声明式事务必须的,所以才认为不适合.

2.1 Act 的依赖注入机制与应用

下面我们就 javadrink 同学上面的关切来谈谈 Act 的依赖注入机制与应用.

这里是来自 Wikipedia 对依赖注入的定义 "In software engineering, dependency injection is a technique whereby one object supplies the dependencies of another object". 简单地说就是对象的状态不由自己来创建, 而是交给另外的对象来注入. 举个例子:

public class UserService {
	@Inject
	private Dao<User> userDao;
	
	@GetAction("/users/{userId}")
	public User get(String userId) {
	    return userDao.findById(userId);
	}
}

上面是一个简单的 UserService 端口. 其中需要使用对应与 User 实体类的 Dao. 在上面的代码中我们没有看到 userDao 是如何初始化的, 因为 userDao 是 Act 框架在实例化 UserService 的时候注入的. 这就是一个典型的 Act 应用依赖注入的方式. 当然 Act 对于依赖注入的使用还有其他的扩展. 我们稍后会提到.

2.1.1 为什么不用 Guice 或者 Spring

这个和Spring或Guice的功能重叠了。直接引入Spring或Guice的不好吗?

现在我来回答 drinkjava 的这个问题: "直接引入 Spring 或 Guice 的不好吗?". 实际上在开发 Genie 之前 Act 尝试过另外两种依赖注入:

在 Act 正式发布之前, 这上面两种注入都曾经在 act 0.x 版本中进入过实际项目 (当然是老码农所在公司的 - 开坑自己先踩是老码农做开源的基本原则).最终我选择了自己开发 Genie 来提供 Act 的依赖注入, 主要原因有一下几点:

  • Feather 的实现足够简单轻量; 但并不是 JSR 330 的完整实现, 比如不支持方法注入, 对 Scope 的支持不完善, 扩展性不够好
  • Guice 提供了完整的 JSR 330 实现; 但同时也引入了一些额外的特性, 比如 Servlet 集成等. Guice 的代码实现也相对比较晦涩.
  • Spring 的依赖注入至始至终都不是我的一个选项, 首先 Spring 的依赖注入不是 JSR 330 标准的实现, 另外 Spring 的依赖注入运行时效率太低 (参见依赖注入性能测试项目).

最终 Feather 简洁的代码实现激励了我启动 Genie 项目, 这个依赖注入库完整实现了 JSR 330, 同时提供了一些有趣且实用的扩展, 比如注入集合类型数据以及注入值数据 等, 这些扩展对实现 Act 里面的 @LoadResource, @LoadConfig 还有 @Configuration 等机制至关重要. 另外因为代码实现比较紧凑, 运行时效率也很不错, 在多项测试中都领先 Guice; 具体数据可以参考这个项目

2.1.2 依赖注入扩展 I - 请求处理方法参数的注入

接下来说说 Act 对传统依赖注入的第一个扩展扩展: 注入请求处理方法参数.

上面那个 UserService 的例子是经典的依赖注入使用方式, 除了将依赖注入字段, Act 还允许直接将服务注入请求处理方法, 例如:

@GetAction("/users/userId")
public User get(String userId, Dao<User> userDao) {
    return userDao.findById(userId);
}

上面代码中, get 方法有两个参数, userIduserDao, 其中 userId 绑定到 URL 路径参数, 假如请求是 /users/abc123, 那 userId 的值就是 abc123; 而第二个参数 userDao 就是依赖注入了, 这个和前面注入到 userDao 字段是一样的. 但

又例如:

    @PostAction("login")
    public void login(String email, char[] password, ActionContext context) {
        User user = userDao.findByEmail(email);
        badRequestIf(null == user, MSG_BAD_EMAIL_PASSWORD);
        badRequestIfNot(user.verifyPassword(password), MSG_BAD_EMAIL_PASSWORD);
        context.login(user);
    }

上面代码中的 ActionContext 也是依赖注入的对象, 而 email, password 则绑定自请求参数.

2.1.3 依赖注入的扩展 II - 资源和配置参数注入

得益于 Genie 的扩展机制, Act 中可以很轻易地注入加载资源和配置参数.

public static class Dao extends MorphiaDao<Contact> {

	@LoadResource("industry_type.mapping")
	private Map<String, String> industryTypeMapping;

	@Configuration("sql.url")
	private String jdbcUrl;
    
	...
}

上面的代码来自实际项目, 其中使用了两种扩展注入:

  • @LoadResource("industry_type.mapping) 将资源文件 industry_type.mapping 的内容加载进 Map<String, String> industryTypeMapping 字段
  • @Configuration("sql.url") 将配置项 sql.url 的值加载进 String jdbcUrl 字段

资源文件 industry_type.mapping 的内容为:

AG1 - Agriculture=Agriculture
AG2 - Agribusiness=Agribusiness
AG3 - Hospitality=Tourism and Hospitality
AG4 - Food Manufacturing/Processing=Food Manufacturing/ Processing
...

可以看出依赖注入在这种场景的使用减少了 boilerplate 代码的使用, 让应用代码变得更加简洁易懂.

值得一提的是 @LoadResource 除了可以注入上面显示的 Map<String, String> 类型, 还能注入很多其他类型, 包括:

  • List<T>
  • File
  • InputStream
  • ...

更多关于 @LoadResource 的示例参见 resource loading 示例项目.

2.1.4 依赖注入机制总结

通过上面关于依赖注入机制的介绍, 可以看出依赖注入在 Act 应用中是基本的机制, 其适用范围远远超出了 drinkjava 同学在问题中表达的观点 "DI唯一比较经典的用法只是用来进行声明式事务才需要".

2.2 关于声明式事务和 AOP

按我的观点,DI唯一比较经典的用法只是用来进行声明式事务才需要,从这个角度出发,就必须要DI支持AOP切面功能,而你却没有加入这个功能,这就很尴尬了,当需要声明式事务的时候,不得不引入一个支持AOP的DI工具,例如Spring/Guice/jFinal,这就造成了使用ACT的项目随时都具备了2套DI工具,也就是说你自带的DI工具实际上是多余的,尤其在流行的Boot环境下,各种配置都是建立在Spring-Core这个IOC/AOP工具基础上,别人不大可能移到Genie内核上。

如果说依赖注入并不只是用来进行声明式事务, 将 drinkjava 同学上面的声明换个说法 "声明式事务是 AOP 少数几个经典用法之一" 我觉得倒是可以接受. drinkjava 同学后面讲到 "从这个角度出发,就必须要DI支持AOP切面功能,而你却没有加入这个功能", 这一点我不同意. DI 和 AOP 是完全不同的概念, 我从来不知道 DI 必须支持 AOP, DI 的 Java 标准 JSR 330 也完全没有提到这个特性. 而 Wikipedia 上 AOP 的页面 也根本没有谈到 Dependency Injection 的概念. 把 DIAOP 放在一起 Google 了一下, 发现这篇 .net 的文章详细分解了这两个概念, 比较其异同以及相关性, 有兴趣的同学可以点击进去看看.

Act 目前不支持通用的 AOP, 但 Act 提供的 SQL DB 插件, 包括 act-ebean, act-hibernate 以及 act-eclipselink 都支持声明式事务. 具体应用代码可以参考下面几个示例项目:

act-ebeanact-hibernate, act-eclipselink 对声明式事务的实现机制是不同的.

  • act-ebean 将声明式事务的实现交给 ebean 引擎. 而 Ebean 是采用了 java agent 对代码做增强来实现声明式事务
  • act-hibernate 和 act-eclipselink 对声明式事务的实现机制都在 act-jpa-common 插件中, 是通过 ASM 对代码做增强来实现的.

我并不认为通用的 AOP 对于应用开发来说是一个非常重要的特性, 也一直没有动手做 AOP 的支持. 我的理由如下:

  1. 我认为 AOP 的应用场合并不是非常普遍的, 可能的场景有:
    • 声明式事务 - ACT 有相应的实现机制 (act-db)
    • Auditing (审计) - ACT 有相应的实现机制 (act-aaa)
    • 性能监控 - ACT 有相应的实现机制 (act-core, ASM based MetricEnhancer)
    • 异常处理 - 我不赞同复杂而精巧的异常处理 - 更新的语言包括 .net C# 还有 groovy, kotlin 等都去掉了 CheckedException 这个概念. Web 应用程序的异常处理应该尽量轻量化.
  2. 从框架角度出发以上 AOP 应用场景都不应该交给应用来完全负责, 通过框架或者插件提供专门的支持才是更加合理的处理方式.
  3. 通用的 AOP 的对于应用开发来说太过晦涩, 且容易导致难以调试的功能性以及性能方面的问题.

基于上面的阐述, 我可以断言 drinkjava 同学评论中的说法是不成立的: "当需要声明式事务的时候,不得不引入一个支持AOP的DI工具,例如Spring/Guice/jFinal,这就造成了使用ACT的项目随时都具备了2套DI工具,也就是说你自带的DI工具实际上是多余的". 一句话, 在 Act 中使用声明式事务以及我上面提到的另外两种 AOP 应用场景都不需要 AOP.

另一方面, 即便需要支持通用 AOP 的支持也不一定使用 DI 工具, 即 Proxy-Based AOP. 如果我一定要在 Act 中加入通用 AOP 的支持, 我倾向于 LTW (Load Time Weaving), 即在进行类加载的时候使用 ASM 工具对类进行增强, 这样做起码在运行时效率上要高很多.

3. [意见二] 考虑一下支持多种模板输出,如包括PDF输出 ... 必要时抄源码

另外考虑一下支持多种模板输出,如包括PDF输出,这才是MVC的V层要做的事,可以参见SpringMVC和Jfinal,必要时可抄它们的源码

看到这个建议我感觉 drinkjava 同学可能还不太熟悉 Act 的模板输出机制. views 示例项目展示了 Act 中同时使用多种不同的模板引擎的特性, 包括:

  • beetl
  • freemarker
  • mustache
  • rythm
  • thymeleaf
  • velocity

response-type 示例项目中展示了 Excel 模板的输出 (采用 JXLS 引擎). 可以说 Act 的模板输出框架是足够满足 (同时) 使用多种模板的. 当然到目前我还没有开发 PDF 的模板插件, 这个可以作为今后的一个工作.

至于评论原文中谈到的必要时抄源码, 我这里可以小自豪一下, 老码农做开源没有抄袭源码的习惯, 从 greenscriptplay-morphia, 再到 rythm 系列, osgl 系列 以及 act 系列, 你要是找到了老码农抄袭别人的代码可以大声叫出来, 算我输. 我做开源的理念很简单: 做别人家没有的, 或者比别人好的; 没有理由去抄袭.

另外我也可以不客气地说 Act 的对输出的支持包括后台模板渲染应该很少有框架能匹敌. 不同意的话我们可以专门讨论一下这个话题.

4. [意见三] 集中精力在 MVC

这里回答 drinkjava 同学评论的最后一部分:

jFinal的问题是DAO、IOC、MVC混成一团,是优点,更是一个大缺点,希望你将主要精力集中在MVC,将它做成一个精致、干净的后台表现层,不要介入任何DI、AOP、DAO、事务的工作,这方面优秀的、流行的工具太多,没必要重造轮子。你现在这个HTTP内核也是自已做的,为了一点点效率或钻牛角尖的小特性,放弃通用性,也是冒风险的,在项目MVC架构选型的第一步就可能被Pass,如果能将HTTP内核和MVC分开,比如说ACT的MVC即可以和自已的内核合用,也可以和Jetty或内嵌Tomcat内核合用,这才是一个比较优秀的架构。

  1. "希望你将主要精力集中在MVC,将它做成一个精致、干净的后台表现层" - 在博客开头我也有讲, Act 并不是一个 MVC 工具, 而是 Web 应用框架以及运行时平台. 另外 "后台表现层" 是个什么鬼? 原谅我读书少, 理解不了这个术语 ^_^.
  2. "这方面优秀的、流行的工具太多,没必要重造轮子" - 这句话我不太赞同, MVC 本身优秀的,流行的工具也很多,SpringMVC 就是一张大伞, 按照这个说法, Act 干脆就不要做了. 我的策略是, 首先看市面上有没有满足自己要求的, 有就用 (比如以前的 Play 1.x, FastJSON, JXLS 等等), 没有就自己做 (比如 Rythm, Act, Genie 等等). 另外 drinkjava 同学自己也造了很多轮子, 包括 DI/AOP 工具 JBeanBox数据库访问工具 JSqlBox 等等. 这意思是说你的工具很优秀, 老码农的水准不够, 就不要玩了吗 ;-)
  3. "你现在这个HTTP内核也是自已做的,为了一点点效率或钻牛角尖的小特性,放弃通用性,也是冒风险的". - 这里 drinkjava 同学高看我了, Act 的 HTTP 核心实现是 JBoss 的 Undertow. 我有打算在未来的版本中迁移到 Netty 上去. 不过我想问问 drinkjava 同学, 你说的 "钻牛角尖的小特性"是指什么? "通用性" 又是指什么?
  4. "如果能将HTTP内核和MVC分开,比如说ACT的MVC即可以和自已的内核合用,也可以和Jetty或内嵌Tomcat内核合用,这才是一个比较优秀的架构。" - Jetty 和 Tomcat 是基于 Servlet 架构的 (不是 HTTP 网络层核心, 而是 API 层的架构), 我认为 Servlet 架构背负太多的历史包袱, 对于现代 Web 框架来说并不是一个很好的选择. 至于 Act 是否是一个比较优秀的架构, 我并不是特别在意. 能在开发时提供友好的支持, 运行时提供足够的性能就好.

最后再次感谢 drinkjava 的评论, 很认真, 信息量很多, 所以我也很认真地使用一篇来回答你的评论.

© 著作权归作者所有

罗格林

罗格林

粉丝 337
博文 48
码字总数 54355
作品 4
其他
架构师
私信 提问
加载中

评论(24)

我叫金正恩
我叫金正恩
时代不同了,自造轮子没啥问题。
yong9981
yong9981
谢谢老罗认真的回复,我也逐条再回复一下,只是个人观点,供参考:
1. 一个 MVC 工具为什么要引入 DI 依赖注入
这个是我搞错了,我一直在找一个干净的MVC工具, 但很可惜ACT不仅是MVC工具,而是一个集成框架,也就是说它是建立在一个IOC内核上的后台集成环境,和SpringBoot的架构类似。这个不是我的菜,因为我只想要一个薄薄的MVC层,并不要它干涉其它方面,就算是依赖于DI工具,也必须能自由切换DI内核,请原谅我急切之下想改造Act成纯MVC工具的冲动。

2.关于声明式事务和AOP
这个的出发点是项目用到数据库,就很可能要上声明式事务功能,也就是AOP功能,你把本应集成在IOC工具里的AOP作为DB工具的一部分单独提供,这个玩的好象大了点,如果人家用的是Mybatis、SpringJdbcTemplate、DbUtils等其它DAO工具怎么办?Spring提供JPA集成有商业因素,这个和IOC内核和插件独立这个架构是背道而驰的,你也学它的,结果就是负担太重,一个人提供不了这么多插件。
DI为什么必须和AOP绑定,是因为DI工具可以根据配置来决定是否生成Proxy,这是一种解耦,使用者无需指明用enhence或duang这类方法。如context.getBean(UserServ.class); IOC工具用统一的入口根据配置来获取一个Bean单例或Proxy单例,底层的IOC工具就能做得很好的事,为什么非要让上层的MVC工具来插一脚?你说的LTW(Load Time Weaving),实际上正是DI+AOP这种底层工具的基本功能。

3.通用的AOP为什么需要?
很简单,因为通用啊,它建之在AopAlliance接口标准上,只要符合这个接口的AOP插件就可以混用。你想想看你的ACT集成环境是否能直接使用Spring的声明式事务?如果不能,即然你能写IOC工具,能写ASM代理,为什么不考虑支持AopAlliance标准。只要支持了这个标准,你就不用为每个DAO工具去写事务插件了。

4. 考虑一下支持多种模板输出,如包括PDF输出 ... 必要时抄源码
这个是我没想到这么多,没仔细读说明。另外说一下,开源抄源码一点都不可耻,说明能合理利用已有资源,不重复造轮子,当然要在尊守开源协议的基础上。
yong9981
yong9981
5. 集中精力在MVC 这个就不再提了。“后台表现层”就是后端渲染的意思,和前端渲染对立,为什么希望找一个薄的MVC层,也是因为前端渲染发展很快,越来越向模块化、拖拽化发展,所以不希望后端技术太复杂,做到极致,将来会是GoSqlGo这种薄后端框架。 6. 流行的工具太多,没必要重造轮子 我的基本思路是后端各个模块要分清,做DAO的、做DI的、作MVC的各自做到极致,互不干拢,同级之间只与同类产品竟争,各领域最优的模块整合到一起就必然是最优秀的集成环境。我做的jBeanBox、jSqlBox虽然不成熟,但在架构、功能和源码精简方面,自信超过大多数同类软件了。反之,如果走整合化的路子,如jFinal、NutzBoot、JBoot之类,本身就先天不足,最基础的IOC/AOP内核比不过Spring-Core、Guice,应用方面DAO比不过JPA、MyBatis,事务比不过Spring,要想从Spring生态中冲出来,实在是难。你这个还算好的,至少还引入了JSR标准,有些集成环境完全自成体系,根本不考虑与现有的接口、规范靠扰,这样的集成环境再多,对整个Java生态也没有帮助,因为其中有用的模块不能抽取出来复用。 7. 你现在这个HTTP内核也是自已做的 这个我也搞错了,应该是undertow。钻牛角尖的小特性指的是类热加载、启动速度、运行速度这些,现在硬件不断在发展,瓶颈在人力替换成本、学习成本这块,性能并不是第一重要的,规范化、模块化更重要,如果为了热加载而引入非标准的Web技术,如丢弃Servlet,会增加维护和招人成本。
罗格林
罗格林 博主
4. 关于 Servlet 我认为 Servlet 越来越成为一个实现规范, 而不是应用规范, Spring MVC 开始就逐渐开始屏蔽 Servlet 的接口, 应用只需要写自己的控制器, 而不是继承某个 Servlet 任何写 doGet, doPost; 到 Spring WebFlux 你能看到多少 Servlet 的影子? TFB 上 Java 的测试框架有几十个(https://www.techempower.com/benchmarks/#section=test&runid=51274292-fa20-4316-bc29-4138d6ac607e&hw=ph&test=db&l=zik0vz-v&c=4), 你去看看有多少是使用了 Servlet API 的. "放弃 Servlet 会增加维护和招人成本" - 我不同意这个结论.
yong9981
yong9981
只是举个例子而已,正巧取了个老古董的不当例子,我的意思是Http内核不需要自已开发,能从市面上选择并可自由切换最流行的前几个Http服务。实际上你已有这个打算,这一点不需要再多讨论了。如果将来Servlet不再是流行的http服务标配,那么丢弃确实也没关系,但这个丢弃还是保留的决定不取决于MVC工具,而是取决于http服务本身的发展。
罗格林
罗格林 博主
我理解你的意思. 不过我可能还没有把我的意思表达清楚: Servlet 不是 HTTP Core, Servlet 是应用框架, HTTP 是协议核心实现, 对于 Tomcat 来讲 HTTP 的实现在 coyote 包里面, 和 Servlet 完全没有任何关系, 而 Tomcat 对 Servlet 的实现则构建与 coyote 包里提供的 HTTP 实现之上; 这个和 Act 使用的 osgl-mvc 应用框架构建在 undertow 的 xnio 之上是一样的, osgl-mvc 相当于 servlet 框架, 而 xnio 相当于 coyote. 但因为 Servlet 规范历史包袱很重, 越来越不适用与当前的 Web 应用开发, 因此从 Spring MVC 开始各种 Java web 框架都尽量避免让应用直接和 Servlet API 打交道; 这样依赖 Servlet 的地位就很尴尬了, 既不是应用框架, 本身又不是 HTTP 核心, 所以就只能成为 Servlet 容器的粘合剂. 整个架构就成为 app -> framework - servlet -> servlet container -> http core, 更多的新框架 (包括 Act 和 Play 等) 都认为其中的 servlet -> servlet container 完全是多余的, 所以就直接摈弃掉这两个, 变成 app -> framework -> http core, 这样以来性能更好, 调用栈更少, 系统更简单稳固, 发布也更容易. 所以说 Servlet 不是 HTTP 服务, 更不是 HTTP 服务标配, 摈弃掉 Servlet 也完全不取决于 HTTP 服务的发展 (比如 http 1.1 -> http 2), 完全是应用框架的选择.
罗格林
罗格林 博主
谢谢 @yong9981. 很高兴能和你一起客观地探讨这些技术问题. 1. 关于"干净"的MVC工具 我不太认同这一点, MVC 的入口是从 C 开始的, 从路由到会话处理到应用本身的请求处理方法,整个过程都在框架的控制之下; 而应用定义的请求处理方法返回之后, 又再次进入框架范围直到响应被生成发送出去. 从这个意义上来将, MVC 蕴含的语义是框架,是反向控制 (IOC), 而不是工具类(由应用来控制调用). 对于任何一个请求的处理, 框架是掌控全局运行环境 (Context) 的, 框架也有义务充分利用 Context 来降低应用的复杂度, 提高对标准的适配能力, 甚至左右系统的性能调节. 基于这个点, 一个薄的 MVC 层对我来说没有任何吸引力, 必须是一个集成的框架才能实现复杂的运行环境需求.
yong9981
yong9981
在我来看,MVC并不是很关键的一层,它主要的工作是接收http服务器参数、转发给Java方法、在后台渲染页面并返回给http服务器, 如果能做得薄一点,做成一个库,而不是一个框架,能够快速上手,适应最流行的几个http服务内核,意义更大。它是有可能设计成不依赖于DI工具的,就算采用DI工具,也应该只让这个DI工具的作用限于方法转发,对用户不可见。而不应该试图用这个DI工具来作为项目的核心。因为DI是关键中的关键,DI工具决定了整个生态,就好象SpringBoot基于spring-core, jBoot基于Guice, NutzBoot基于Nutz.Ioc,将来可能出现自由切换DI内核的Boot生态,但现在没看到。ACT的主要功能是MVC转发和渲染,但为了这两个功能,放弃其它生态而切换到ACT来,是有风险的,一些其它功能,如sharding、分布式事务、定时任务等,用主流的生态是现成的,但切换到ACT来就要从头学习DI怎么配置出来。不是不能搞生态,而是MVC不一定要通过生态的方式来提供,做成库的代价更小。
罗格林
罗格林 博主
基于 Guice 的应用都可以轻易切换到 Genie, 因为都是 JSR 330 的实现, 其他的就不说了. 另外几个功能: Sharding 和 分布式事务和数据库访问层紧密相关, 不可能在框架内统一, 必须交给数据库访问插件; 定时任务在 Act 里面已经做掉了, 当然启动定时任务的应用逻辑肯定是需要 DI 来做的, 这也是整个框架不能作为一个库的原因. 库的意思是给应用调用, MVC 做成库, 应用如何调用?
yong9981
yong9981
可以做成带main入口的库,或者做成标准的servlet过滤器。比方说把jFinal去掉DAO模块,去掉@Inject功能,去掉著名的duang方法,剩下的就是一个还算干净的不依赖于DI工具的MVC库了。至于DI/AOP功能,这个不用担心,可以把DI容器上下文配置到MVC工具里,在项目的任意地方都可以使用它就可以了。如果是单上下文应用就更简单了,都不用配置到MVC工具里,直接用静态全局方式调用getBean之类的方法就可以了。
罗格林
罗格林 博主
不管是一个 main 入口还是标准的 Servlet 过滤器, 应用的主要逻辑都是被框架调用, 运行环境的控制还是在框架之中; 不可能把这个东西叫做库. 所谓库指的是 hutool, apache-commons, osgl-tool 这一类的东西, 提供各种方法供应用调用. MVC 从本质上讲就是框架而不是库. 这个方面我们之间的理念差异太大, 谈到这里可以停下来了.
罗格林
罗格林 博主
[2. 关于声明式事务和AOP] 我认为数据库插件这种东西不管是否使用通用 AOP, 工作量都不会太少 (当然也不会太大). 而需要支持的数据库访问方式就那么几种. 即使以后有新的数据库访问需要集成, 我觉得工作重点应该放在插件文档上面, 而不是通用 AOP. 另外关于 LTW,这个工作是不可能在 DI 工具下面完成的,因为 DI 根本就没有设计类加载机制. 当然这个机制本身和单纯的 MVC 并没有关系, 而是整个框架的基础设施, 对于 Act 来说就是 AppClassLoader 和各种 Scanner/Enhancer 构成的基础计算环境. DI 仅仅是为这个环境服务的一个工具, 如果将来有了通用 AOP, 也是为这个环境服务的一个工具.
罗格林
罗格林 博主
[3. 为什么我不需要通用的 AOP?] 文章中已经说得很清楚, 再重复一下: Act 能够支持声明式事务, 能够支持声明式事务, 能够支持声明式事务. 至于是否为每个 DAO 写声明式事务, 上面已经说过了, 不管你是否要写声明式事务的之后, 插件都是必须要写的. 我可以再明确一点: 数据库插件不仅仅是声明式事务!
yong9981
yong9981
能实现不代表是个好的实现,就好象jFinal的声明式事务用着也不错,但是如果用jFinal整合Spring的支持嵌套的声明式事务试试? AOP联盟标准是一个比较正常的手段,可以解决AOP插件互换性的问题,而不用从头开发插件。 当然,如果你添加了AOP联盟标准功能,就相当于geine这个IOC/AOP工具完整了,你可以拿来对标Guice了。我不鼓励谁都去搞集成环境,一两个人是搞不好的。但一两个人搞工具,进行同类项目竟争倒是不错的,因为工具是可以互换的,一个工具不好可以随时换掉。
罗格林
罗格林 博主
Genie 作为 JSR 330 的实现本来就是对标 Guice, 至于 Guice 后来加上的 AOP, 我认为在 Act 的框架下应该有其他实现方式 - 我文中谈到的直接用 ASM 增强做 LTW, 应该比在 Genie 中模仿 Guice 加上 AOP 的实现要好.
yong9981
yong9981
对于作为项目平台的DI工具来说,性能不是唯一要考虑的,和MVC经常频繁创建新的对象实例不同,项目的DI工具往往只用到了单例容器,对于单例来说,都是从缓存中取所以不存在性能问题。相反通用性和功能全面性是它要考虑的,除了JSR330外,JSR250也很重要(即单例容器),AopAlliance也很重要,以及没有源码情况下如何装配对象(这是Guice的短板,可以对比在没有源码情况下Spring和Guice如何注入构造器带参数的对象),以及有没有循环依赖检测等。LTW对于性能提高这点实际上并不重要(因为大多是单例),反而配置起来麻烦,Spring也可以配置成LTW模式,但很多人可能用了一辈子Spring都不知道有这么个功能。
罗格林
罗格林 博主
JSR 250 我的理解更多是为 JEE 容器服务的, 暂时还没有进入我的雷达, 只有 PostConstruction 语义和依赖注入紧密相关, 所以 Genie 会处理这个注解. AopAliance 即 通用 AOP 我对它的意见已经说了很多了, 就不再重复; 没有源码的情况下如何装配 - 我没有考虑不符合 JSR330 的情况; 循环检查 - 依赖注入工具的基本要求, Genie 已经提供. LTW - Spring需要麻烦的配置不等于其他实现也需要.
罗格林
罗格林 博主
@李嘉图

你说的大概是 Proxy Based AOP, 当需要 weave 某个 cross cutting point 的时候, **使用** DI 工具来注入一个类(或者接口)的 Proxy (AOP 框架实现), 而不是直接类或者接口的实现. 从这个意义上来说, AOP 框架可以利用 DI 工具来实现某种类型 (Proxy-Based) 的 AOP, 然而具体 Proxy (需要 weave 进去的逻辑) 的实现还是 AOP 的工作, 和 DI 无关.

当然 AOP 还有其他方式的实现, 比如 aspecj 就是在编译时 weave 进逻辑, 这个操作是直接在切点相关的类上做工作, 和 DI 完全没有关系了.

如果 Act 将来一定要实现通用的 AOP 的话, 大概率会采用 Load Time Weaving, 差不多也是采用 aspectj 的方式, 直接在类字节码上用 ASM 做操作, 只是在类加载的时候 weave, 而不是编译时. 这个操作也和 DI 没有关系. 这样做的好处是没有 Proxy based AOP 的限制, 而且运行时性能要好很多.
李嘉图
李嘉图
aspectj 差点忘了这个了,的确这个是编译时候做的,不过肯定需要插件的支持,我说的的确是Proxy Based AOP. 还有 @drinkjava 说的你的mvc不支持多模板输出这个的确不科学,现在那个mvc不支持多模板输出呢,只不过mvc主要支持渲染ajax和html,其余的可能需要自己实现而已罢了
李嘉图
李嘉图
你要是类似aspectj的话,那就是编译的时候做,需要插件的支持,这样性能可能高一些,但是如果是动态生成的类需要代理的话,你那里恐怕就做不到了吧?
罗格林
罗格林 博主
不会是 CTW (Compile Time Weaving), 只会是 LTW (Load Time Weaving), Act 在加载类的过程中进行 weave, 只要符合条件的类, 不管是已经编译好的, 还是动态生成的都应该被处理. 这种基于 ASM 对类进行增强的操作在 Act 框架中并不少见.
李嘉图
李嘉图
😄😄强大,我以后要写asm的代码了,首先就是参考你的写
罗格林
罗格林 博主
Act 对输出的支持可不仅仅限于基于模板的输出. 控制器返回同样的数据框架会基于请求的 Accept 头生成不同的输出, 比如 XML, JSON, YAML, CSV, XLS, XLSX 等等 另外同样一套代码也可以被模板覆盖, 只需要在模板文件后面放置不同的扩展名, xxx.html, xxx.json, xxx.xml ...; 而项目中甚至可以同时有多套模板引擎, 每个引擎有自己的 id 和资源目录. 这样的设计, 你的控制代码完全不变, 但输出的种类就很多了; 你试试 Spring 或者其他框架能不能控制器代码完全一样, 依照 Accept 头生成 HTML 和 Excel 输出的?
李嘉图
李嘉图
晚上看了没看懂,明天早上再看一遍,不过,我认为,AOP和DI虽然没有关联,但是DI作为程序new的全局入口,天然适合搞AOP,所以,有了DI,便支持AOP这个是很自然的事情
ActFramework 1.0 正式发布, Java MVC 框架

ActFramework 是一个Java的非轻量级全栈式MVC框架. 和其他框架相比ActFramework的主要特点有: 热加载. 开发过程(包括新增方法变量)不需要重启系统, 随时可以看到最新代码的效果 强大的参数绑...

罗格林
2017/03/09
6.7K
72
drinkjava2/jWebBox

(English version see README-English.md) jWebBox License: Apache 2.0 这是一个服务端(支持JSP和FreeMaker)页面布局工具,特点是简单,无XML,仅用400行源码实现了与Apache Tiles类似的页面...

drinkjava2
2018/01/02
0
0
act-starters 发布,让 #actframework 应用开发更简便

act-starters 是一系列简化 #actframework 应用依赖管理和其他 maven 构造处理的工具. 现在已经发布了 12 种 starters: act-starter-beetl - 使用 beetl 为默认模板引擎 act-starter-ebean2...

罗格林
2018/01/03
546
11
drinkjava2/jSqlBox

jSqlBox License: Apache 2.0 jSqlBox是一个Java持久层工具,设计目标是用来代替目前的Hibernate/MyBatis/JdbcTemplate/DbUtils等持久层工具。jSqlBox的主要特点: 模块化设计。 jSqlBox将Jdb...

drinkjava2
2017/03/11
0
0
如果你会AngularJS,不妨做一下这份自测卷

  【IT168 评论】AngularJS似乎很老了,它比Angular2长了7岁,比Vue.js长了5岁,比ReactJS长了4岁。虽然年老,但在很多项目中都可以看到AngularJS的身影。它在Github上拥有1500多位贡献者,...

it168网站
2017/11/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用zabbix自带的模板监控MySQL自带

一、安装zabbix server 略 二、安装zabbix agent 略 三、给主机套自带的模板 略 四、创建授权用户 mysql> grant all on *.* to 'zabbix'@'localhost' identified by 'musingtec2019';Quer......

雁南飞丶
12分钟前
4
0
notepad++快捷键

notepad++也情有独钟,最近发现了一个快捷键,就是选中单词,ctrl+shift+enter。不过现在想知道一个快捷键,假设有三行代码,选中后一般按TAB就可以三行全部缩进. Notepad++绝对是windows下进...

zhengzhixiang
33分钟前
5
0
区块链背景是什么?区块链的意义是什么?

一、前言 区块链技术的首次也是最著名的应用是比特币,一个在2009年1月初正式上线运行的去中心化数字货币应用,他的创始人叫中本聪,但目前大家并不知道此人的真实身份。 比特币不同于现代国...

daxiongdi
38分钟前
4
0
在Bash中循环浏览文件内容

如何使用Bash遍历文本文件的每一行? 使用此脚本: echo "Start!"for p in (peptides.txt)do echo "${p}"done 我在屏幕上得到以下输出: Start!./runPep.sh: line 3: syntax error......

技术盛宴
41分钟前
8
0
史上最强IP正则表达式

port ([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{4}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]) ipv4 ^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$ ipv4+mask......

蜗牛伊
44分钟前
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部