Hasor-Core:启动环境和模块

ta8210 2013-07-31

首先引用Wiki的介绍一下Hasor:

    “Hasor是一款开源框架。它是为了解决企业模块化开发中复杂性而创建的。Hasor遵循简单的依赖、单一职责,在开发多模块企业项目中更加有调理。然而Hasor的用途不仅仅限于多模块项目开发。从简单性、松耦合性的角度而言,任何Java应用都可以从中受益。Hasor与Struts,Hibernate等单层框架不同,它可以提供一个以统一、高效的、友好的方式构造整个应用程序。并且可以将这些单层框架建立起一个连贯的体系,可以说Hasor是一个搭建开发环境的框架。这一点与Spring比较相似,您可以理解Hasor可以作为Spring之外的一种选择。”

   再次 非常感谢各位关注Hasor的同僚们,在发布Hasor的有关消息之后在OSChina上得到了很多朋友的询问和关注。在此表示感谢 ! 这篇文章主要是介绍Hasor的体系是怎么设计的,通过了解本文的<模块启动支持>章节内容您可以知道在hasor中模块会得到哪些来自于底层的API支持。下图是Hasor启动过程。

all-life-process

整个hasor底层支持代码都存在于hasor-core项目。其中可以进一步分为3个相对独立的子系统。它们是:

  1. 启动环境支持(InitContext接口及其相关服务API,在doStart过程之前完成创建【如上图】)
  2. 模块支持(其中包含了模块启动和模块结构两个部分)
  3. 应用程序支持(AppContext接口及其相关API,当进入Run阶段时AppContext就已经完成创建【如上图】)

一、启动环境支持

initcontext-support

上面这张图显示了模块启动环境中所有相关部件的构建关系。其中红色部分InitContext接口是Hasor在启动环境这一块提供的最终API。启动环境中包括了下面4个部分:

1.EventManager:事件服务:(事件机制、同步事件、异步事件、Timer服务)

    事件的支持是由EventManager接口封装并且位于启动环境支持中,通过InitContext的getEventManager()方法即可获取到事件服务的API。它本身是观察者模式的具体实现。使用Hasor的事件机制可以提高程序的重用性,可维护性,在模块的职责划分上可以清晰的标出界限。

    打个比方:你有一个文件上传服务,上传的文件根据其格式会进行不同的后续处理。使用事件机制你可以在文件上传完成之后抛出不同的事件。将不同的处理封装到不同的事件监听器中,这样的设计既可以降低代码耦合度又增加了可维护性。在Hasor中使用HasorEventListener接口开发处理程序,使用@EventListener注解注册事件监听器。当然您可以使用代码方式动态的创建事件监听器并且注册它。

    异步事件:对于那些在Web环境下上传完文件要即时响应客户端但同时要马上进行长时间处理的程序而言。Hasor的异步事件服务可以帮助你解决问题。异步事件的特性就是发出事件交给线程池安排执行任务。从而不需要发起程序等待事件执行结束。

    Timer服务是一个更为简单的工具,常常在实际开发中会有一些不太重要的定时任务。这种事情可以交给Hasor的Timer服务进行调度,它会每隔一段时间触发一个事件。

2.Environment:环境变量(提供读取系统环境变量和Java系统属性的接口)

    你是否想过可以在应用程序中解析这样一段文本“%JAVA_HOME%/bin/javac.exe”当在系统环境变量上配置了JAVA_HOME环境变量的情况下你可以轻松的得到javac.exe的实际路径。在没有Hasor环境变量功能的情况下,实现这个功能是需要简单写一段代码来实现的。

3.WorkSpace:工作空间(目录规划)

    工作空间的概念是用来帮助开发者在开发程序中遇到需要保存磁盘上的数据做一个合理的规划和布局。Hasor在工作空间上规划了6个功能目录。它们是:

  • workDir:程序工作空间基础目录(绝对路径)
  • dataDir:程序的数据目录(相对路径)
  • tempDir:程序在运行时产生的临时文件目录(相对路径)
  • cacheDir:程序执行中产生的缓存数据目录(相对路径)
  • logDir:程序执行中产生的日志目录(相对路径)
  • pluginDir:插件目录,该目录是为每个模块提供的独立目录空间,可以用于保存模块配置(相对路径)

    上面的5个目录是hasor在设计之初就规划的好的,其中workDir被设计成为其他目录的父目录。通过配置文件的配置除workDir之外的5个目录都可以使用绝对路径来表示,这样做可以方便程序在实际环境中的部署应用。
(Home(程序主目录):Home是应该用来表示应用程序所在的主目录。在Hasor中目前没有API可以得到Home路径)

    除了上面6个预定义的目录开发者可以根据自己的需要对目录进行进一步的细分,下面就上面6个预定义的目录做详细的说明。

workDir(工作目录):区别于Home,是程序的工作目录。用于保存程序运行期间产生的所有目录,其子目录会详细区分不同的功能路径。
dataDir(数据目录):该目录被设计用来存放程序主要数据,在Web项目中通常是程序上传的文件、模板文件、动态载入的程序功能配置文件等等。
tempDir(临时文件):该目录不同多说,凡是程序在运行期间产生的临时文件都可以在该目录下保存。其中web程序中上传文件时临时缓存文件可以被存放到这里。理论上该目录中的的数据在应用程序启动之前或结束之后都可以被删除。
cacheDir(缓存目录):如果您的项目会升程静态缓存文件,那么该目录是绝佳的选择,缓存目录的特性是。辅助应用程序运行提高程序运行效率。
logDir(日志目录):存放例如log4j等日志程序产生的日志信息。
pluginDir(插件目录):该目录是为每个模块提供的独立目录空间,可以用于保存模块配置。

4.Settings:配置文件支持(配置文件、配置文件命名空间支持)

    由Settings接口提供,它是唯一可以脱离整个Hasor体系独立使用的部件。其它所有部件都需要依赖它实现,它有一个独立的实现类HasorSettings。Settings接口提供了一组非常方便的配置文件读取API。同时这个部件还支持自动检测主配置文件是否有改变,如发生改变会自动重载整个配置文件。

    在Hasor中配置文件被分为静态配置文件(static-config.xml)和主配置文件(hasor-config.xml)。静态配置文件主要是用于存放缺省配置信息,而主配置文件的职责是用来覆盖缺省配置。从而使开发者不必面对大量不关心的配置参数。

    Hasor在解析配置文件时会将同一个命名空间下的不同配置文件的解析内容合并到一起。然后根据Xpath将其转换为Key/Value键值对形式。例如:

<!-- 系统内置帐号信息 --> 
<loginSafe enable="true"> 
    <!-- 登陆表单递交位置 –> 
    <loginFormURL>/s_j_check</loginFormURL>
</loginSafe>
------------------------映射结果为------------------------
系统内置帐号信息
loginSafe = <XmlProperty类型对象>

loginSafe元素的enable属性
loginSafe.enable= true

登陆表单递交位置
loginSafe.loginFormURL = /s_j_check

    使用Hasor的Settings获取配置信息时它会忽略大小写敏感。在上面的例子中使用“ loginsafe.enable ” 或 “LOINGSAFE .ENABLE ” 都可以获取到映射的属性值 “true”。同时Hasor的Settings可以根据调用方法的不同对相同的配置信息可以返回不同的类型(当类型可以被转换时)。 

    不光如此通过Settings的getXmlProperty(...)方法获取到的配置项可以以DOM的方式操作他。例如上述配置例子,使用getXmlProperty("loginSafe")可以获取到loginSafe的Xml节点。然后可以使用下面这些方法对其进行DOM操作:

public interface XmlProperty {
    /**获取Xml节点元素名称。*/
    public String getName();
    /**获取Xml节点文本值。*/
    public String getText();
    /**获取Xml节点Xml文本值。*/
    public String getXmlText();
    /**获取属性集合*/
    public Map<String, String> getAttributeMap();
    /**获取Xml子节点。*/
    public List<XmlProperty> getChildren();
    /**获取父节点*/
    public XmlProperty getParent();
    /**克隆一个XmlProperty*/
    public XmlProperty clone();
}

二、模块支持:

在Hasor模块支持部分被分作两个部分,如下图(左:模块信息支持、右:模块启动过程支持):

image

1.模块信息

在Hasor中模块的定义信息是不会通过配置文件决定,因为Hasor觉得配置文件在充当模块配置信息源时并不直接。再加上Hasor的模块定义十分灵活因此也并不适合在配置文件中加以定义。因此Hasor采用的方式是直接从模块对象身上提取必要的信息,其中包括了(模块显示名、模块说明、模块依赖信息)。下面这段代码定义了一个模块,除此之外定义模块不需要在写额外的配置或者代码。

@Module()//声明一个模块,显示名称为Mode1 
public class Mode1 extends AbstractHasorModule {
    /*该方法是在启动生命周期过程之前调用,该方法的主要目的是确定模块启动顺序。*/
    public void configuration(ModuleSettings info) {
        info.beforeMe(Mode2.class);//要求Mode2排在Mode1之后启动
        info.afterMe(Mode3.class);//要求Mode1要先于Mode3启动
        info.beforeMe(Mode9.class);//
    }
    /*模块启动生命周期中init阶段*/
    public void init(ApiBinder apiBinder) {
        System.out.println("Mode1  init!");
    }
}

Hasor会在调用生命周期管理器启动模块之前会率先调用所有模块的configuration方法。该方法可以用于确定模块的依赖信息,然后Hasor会将其转换为下图的结构。

2.模块启动支持

有关模块启动过程相关信息请看这里(http://my.oschina.net/u/1166271/blog/143873

Global site tag (gtag.js) - Google Analytics