【问题标题】:is SFig language syntax efficient and clear (and better than Spring-Framework's XML DSL)?SFig 语言语法是否高效且清晰(并且比 Spring-Framework 的 XML DSL 更好)?
【发布时间】:2010-09-27 22:42:27
【问题描述】:

附录编辑:

尚未接受对此的回答 没有任何反馈 经验丰富的 Spring Framework 开发人员。

我一直在研究用于 Spring-Framework applicationContext.xml 文件的替代 DSL(其中描述了 bean 初始化和依赖关系以加载到 Spring bean 工厂中)。

我的动机是我完全不喜欢 Spring 为此目的使用 XML,也不喜欢迄今为止设计的任何替代方案。出于各种我不会详细介绍的原因,我想继续使用声明性语言,而不是像 Groovy 这样的命令式脚本语言。

所以我使用了 ANTLR 解析器工具,并一直在设计一个新的 bean factory DSL,我称之为 SFig。这是一个详细讨论此问题的链接:

SFig™ - alternative metadata config language for Spring-Framework

这里是源代码存储站点:

http://code.google.com/p/sfig/

我很想知道到目前为止我在语言语法方面的表现如何。您认为 SFig 既高效又清晰易懂? (我现在特别关心多行文本字符串):

properties_include "classpath:application.properties";


org.apache.commons.dbcp.BasicDataSource dataSource {
    @scope = singleton;
    @destroy-method = close;
    driverClassName = "${jdbc.driverClassName}";
    url = "${jdbc.url}";
    username = "${jdbc.username}";
    password = "${jdbc.password}";
    defaultAutoCommit = true;
}


org.springframework.orm.ibatis.SqlMapClientFactoryBean sqlMapClient {
    @scope = singleton;
    @init-method = afterPropertiesSet;
    @factory-method = getObject;
    configLocation = "classpath:sqlmap-config.xml";
    dataSource = $dataSource;
}


/* this string will have Java unescape encoding applied */
STRING str = "\tA test\u0020string with \\ escaped character encodings\r\n";


/* this string will remain literal - with escape characters remaining in place */
STRING regexp = @"(\$\{([a-zA-Z][a-zA-Z0-9._]*)\})";


/* multi-line text block - equates to a java.lang.String instance */
TEXT my_multi_line_text = ///
Here is a line of text.
This is yet another. Here is a blank line:

Now picks up again.
///;


/* forward use of 'props' bean */
java.util.HashMap map {
    this( $props );
}


/* equates to a java.util.Propertis instance */
PROPERTIES props {
    "James Ward" = "Adobe Flex evangelist";
    "Stu Stern" = "Gorilla Logic - Flex Monkey test automation";
    Dilbert = "character in popular comic strip of same title";
    "App Title Display" = "Application: ${app.name}";
    "${app.desc}" = "JFig processes text-format Java configuration data";
}


/* equates to a java.util.ArrayList instance */
LIST list {
    this( ["dusty", "moldy", "${app.version}", $str] );
    [234, 9798.76, -98, .05, "numbers", $props, ["red", "green", "blue"]];
}

【问题讨论】:

  • 我不得不编辑我的帖子以将“JFig”更改为“SFig”。事实证明,已经有另一个以 Java 为中心的编程工具,称为 JFig,并且已经存在多年了。我选择 SFig 来暗示 Spring-Framework 的预期配置关系。

标签: inversion-of-control antlr spring dsl parsing


【解决方案1】:

我将提供一些关于 Spring 的背景知识,它是 applicationContext.xml 文件 - 这将使 SFig 语法中发生的一些事情变得清晰。

applicationContext.xml 文件用于表示将由 Spring bean 工厂管理的 bean 的 bean 初始化。因此,鉴于我在此文件的 SFig 版本中看到的 bean 示例,在 Java 应用程序代码中,可能会请求 bean 工厂创建一个 bean 的实例,如下所示:

SqlMapClient sqlMapClient = getBean("sqlMapClient");

bean 工厂负责 bean 所需的任何实例化和初始化 - 甚至到注入依赖项的程度。在这种情况下,SqlMapClient bean 需要一个 dataSource bean 的实例(在 SFig 示例中也有描述和引用)。

一个 bean 描述符将以下信息传递给 bean 工厂:

  • bean 的 Java 类名
  • 请求或引用它的 bean ID
  • bean 定义元属性(可选)
  • 构造函数初始化参数(可选)
  • 和/或属性初始化器

'@' 前缀 bean 定义元属性。这些是 bean 工厂用来管理 bean 的属性。例如,@scope = singleton,将通知 bean 工厂创建 bean 的单个实例,缓存它,并在请求时分发对它的引用。可以设置的和Spring-Framework定义的一样。

如果要通过构造函数初始化 bean,那么在 SFig 中,它会通过一种语法来表达,该语法似乎是在调用 this,并带有括号中的参数。

或者可以通过设置它的属性来初始化一个bean。分配给但不以“@”为前缀的标识符是 bean 属性。

当引用作为必需依赖项的 bean 时,可以通过在其 bean ID 前加上“$”前缀来引用它。 SFig 示例中出现了几个这样的示例。

出现在字符串文字中的变量的 ${foo.bar} 样式将被 Java 属性值替换。在这种情况下,属性是通过以下行从文件 application.properties 加载的:

properties_include "classpath:application.properties";

如果在任何包含的属性中都找不到 Java System 属性,则将查找下一个。这是许多 Java 框架中广泛遵循的做法。当前基于 XML 的 applicationContext.xml 文件也有一种允许这种用法的方式。

因为 java.util.Properties 经常用于初始化 bean,所以 SFig 提供了 PROPERTIES 作为一种特别方便的语法来声明一个 Properties 对象。 java.util.List 也是如此,它具有相应的 SFig LIST。此外,值数组可以在方括号 [...] 内声明。

另外还有用于声明多行文本块的 TEXT。字符串文字前面的“@”表示关闭转义编码——一种从 C# 借来的语言语法。

SFig DSL 的主要设计目标之一是在本质上保持声明性。我故意避免添加任何命令式脚本功能。嵌入在文本配置文件中的编程逻辑的复杂性意味着必须对其进行调试。不想打开代码调试的另一个维度。

【讨论】:

    【解决方案2】:

    我对您所引用的 Spring XML 没有太多经验,因此您应该对以下反馈有所保留。

    作为第二和第三个警告:

    • 提供代码的 sn-p 将提供语言及其语义的风味。很难完全理解您已经做出的某些选择(并且有充分的理由),因此这里的任何反馈都可能与这些选择完全矛盾或不可能。
    • 语言设计既是一门艺术又是一门科学,因此在这个阶段,您可能得到的任何反馈都可能是相当主观的。

    一个更大的元问题:作为 DSL,您是在尝试配置 Spring,还是作为更通用的框架类?

    那里:买者自负。现在我的主观和不完整的反馈;)

    • 我不确定我是否理解为什么 scopedestroy-method@ 前缀,而不是 driverClassName。此外,xml-case 和 camelCase 的混合在开始时并不完全明显。 @ 前缀是类型修饰符,还是语言中的这些关键字?

    • 我不完全确定您对块头格式的意图。您有类名,然后是该类的函数;是否打算指定您将为特定功能使用的类?

    例如

    sqlMapClient: org.springframework.orm.ibatis.SqlMapClientFactoryBean {
        # body.
    }
    

    甚至:

    sqlMapClient {
        @class = org.springframework.orm.ibatis.SqlMapClientFactoryBean;
        # is there a sensible (perhaps built-in) default if this is missing?
    }
    
    • 我喜欢变量替换;我认为这些值将来自系统属性?

    • 我喜欢能够指定 字符串文字(不转义),尤其是对于您展示的正则表达式。但是,使用多字符引号或引号修饰符似乎有点陌生。我猜你考虑过单引号(shell 和 Perl 对文字字符串使用单引号)。

    • 另一方面,我认为 多行 TEXT 的三重斜杠是正确的方法,但其中两个让人想起 C 风格语言中的 cmets。为此,Python 使用了三元组 "。一些 shell 惯用语有一个多行文本约定,我不会复制。

    • 我非常喜欢属性和配置位置的外观,使用看起来像 URI 寻址概念。如果这是一个 URI,classpath://file.xml 可能更清楚。不过,我可能在这里搞错了。

    • 我也非常喜欢你所拥有的列表和映射文字的概念,尽管我不确定在哪里:

      • this 进入其中(我猜是对 Java 构造函数的调用)
      • 为什么有些类型是大写的,而有些不是。我是否认为有一个默认的 MAP 类型,如果您愿意,您可以使用更具体的类型?
      • Dilbert 是不带引号的字符串文字吗?

    最后,我将向您指出另一个配置 DSL,尽管可能更多地用于系统管理员使用:Puppet

    一切顺利。

    【讨论】:

      猜你喜欢
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2020-04-25
      相关资源
      最近更新 更多