- 浏览: 1704463 次
- 性别:
- 来自: 杭州699号
文章分类
最新评论
-
莫莫摸:
为什么不用dubbo
RCP数据传输模型回顾 -
大胡子爸爸:
String, Class 都实现了Serializable接 ...
RPC框架几行代码就够了 -
lss598018587:
谢谢大神分享,比起新手看复杂的dubbo框架还不如看大神的这一 ...
RPC框架几行代码就够了 -
15606915740:
你好,请问一下。<dubbo:consumer filt ...
Dubbo文档 -
joqk12345:
...
一些设计上的基本常识
注:该博客内容已加入 http://httl.github.io 文档。
HTTL源代码参见:https://github.com/httl/httl/
先来看一下HTTL的类结构设计,类图如下:
查看大图
模型划分原则:按实体域,服务域,会话域划分。
不管你做一个什么产品,都一定有一个被操作的主体,比如:服务框架管理的Service,任务框架管理的Task,Spring管理的Bean等,这就是实体域。
即然有被操作者,就一定有操作者,它管理被操作者的生命周期,发起动作,比如:服务框架的ServiceInvoker,,任务框架的TaskScheduler,Spring的BeanFactory等,这就是服务域。
服务域发起动作,在执行过程中,会有一些临时状态需要存储交换,比如:Invacation,Execution,Request等,这就是会话域。
相应的,在HTTL中:
* Engine 为服务域
* 它是API的入口,并负责实体域Template的生命周期管理,它是Singleton单一实例的,加载后不可变,所以是线程安全的,它的初始化过程较重,请复用单例。
* Template 为实体域
* 代表着被操作者,它是Prototype原型实例的,即每个模板产生一个实例,加载后不可变,同样也是线程安全的,模板变化后,将产生不同的实例,而不改变原实例。
* Context 为会话域
* 持有操作过程中的所有可变状态,它是ThreadLocal线程内实例的,即不和其它线程竞争使用,所以也是线程安全的,请不要跨线程传递,它的初始化过程很轻量,每次模板执行前都新建实例,执行完即销毁。
这样划分的好处是,职责清晰,可变状态集中,每个域都是无锁线程安全的,保证在大并发下,不会降低系统的活性。
这些核心领域模型也就是HTTL的API(Application Programming Interface),它是HTTL暴露给用户的最少概念,也就是上面类图中的第一列。
扩展点组装原则:按“微核+插件”体系组装。
但凡有生命力的产品,都是在扩展性方面设计的比较好的,因为没有哪个产品可以覆盖所有需求,对于开源软件尤其如此。
所以,产品只有具有良好的扩展性,允许用户或第三方参与进来,进行二次开发,才能保持生命力。
怎么样的扩展性才是最好的?通常来讲,就是没有任何功能是硬编码的,所有的功能都可被用户替换。
那要如何才能做到这样?一个重要的原则就是:平等对待第三方。
也就是凡是原作者能实现的功能,第三方也要能够在不改变源代码的前提下实现。
换言之,原作者应把自己也当作扩展者,自己添加功能时,也要用第三方扩展者同样的方式进行,而不要有特权。
要做到这一点,就需要一个良好的框架支撑,“微核+插件”是一个不错的选择,Eclipse, Maven等知名软件都采用该体系。
什么是“微核+插件”?微核,即最小化核心,内核只负责插件的组装,不带任何功能逻辑,所有功能都由可替换的插件实现,
并且,组装过程应基于统一的规则,比如基于setter注入,而不能对不同插件硬编码组装,这样可以确保没有任何功能在内核中硬编码。
比如:Spring, OSGI, JMX, ServiceLoader等都是常见的微核容器,它们负责基于统一规则的组装,但不带功能逻辑。
当然,如果你不想带这么重的框架,也可以自行实现,HTTL就采用自行实现的httl.util.BeanFactory作为组装微核。
在Engine.getEngine()中调用了BeanFatory.createBean(Engine.class, properties),
其中,properties即为httl.properties配置,BeanFatory基于setter方法,递归注入所有对象的属性。
比如:httl.properties中配置了parser=httl.spi.parsers.CommentParser,
而DefaultEngine中有setParser(Parser parser)方法,就会被注入,并且Parser本身的属性也会递归注入。
既然非功能性的插件组装过程,可以由微核框架来完成,那功能性的组装怎么办呢?
我们应该把功能性的组装过程也封装成插件,即让大插件组装小插件,形成级联组装关系。
比如,HTTL的入口类Engine的实例也是一个插件,它负责模板的缓存,加载,解析的总调度,即你可以替换DefaultEngine实现。
只需在httl.properties中配置:engine=com.your.YourEngine,可以将现有Parser等SPI注入你的Engine。
这些插件的接口,也就是HTTL的SPI(Service Provider Interface),它是HTTL暴露给扩展者的最小粒度的替换单元,也就是上面类图中的第二列。
分包原则:按复用度,抽象度,稳定度分包。
* 复用度:
* 每种用户所需用到的类,就是同一复用粒度的,比如:使用者和扩展者,这样可以减少代码干扰,以及最大化复用。
* 稳定度:
* 被依赖包和依赖包的占比,如果一个包依赖很多包,那别的包变化都会引起它跟随变化,所以它就不稳定,反之即稳定,
保持被依赖者总是比依赖者的稳定度高,形成金子塔关系,这样可以防止不稳定性传染,比如a包只依赖3个包,而b包依赖10个包,那就不要让a包去依赖b包。
* 抽象度:
* 包中抽象类个数占比,比如包中有10个类,其中3个为抽象类(包括接口),则抽象度为3/10,
保持包的稳定度和抽象度成正比,即把抽象类(包括接口)放到稳定的包中,把具体实现类放到不稳定的包中,这样可以保持每层都有足够的扩展性。
稳定度与抽象度关系如下图:
也就是分包应该如下:
其中上面那个包不依赖其它包。所以它很稳定,应尽量把抽象类或接口放在这一层,
而下面那个包依赖了三个包,三个包变化都会引起它跟随变化,所以它是不稳定的,应尽量把具体实现类放在这一层。
因稳定度与抽象度成正比,所以不稳定度与抽象度成反比,用反比方便画图,计算方式如下:
* (1) I = Ce / (Ca + Ce)
* I: Instability (不稳定度)
* Ca: Afferent Coupling (传入依赖,也就是被其它包依赖的个数)
* Ce: Efferent Coupling (输出依赖,也就是依赖其它包的个数)
* (2) A = Na / Nc
* A: Abstractness (抽象度)
* Na: Number of abstract classes (抽象类的个数)
* Nc: Number of classes (类的个数,包括抽象类)
* (3) D = abs(1 - I - A) * sin(45)
* D: Distance (偏差)
* I: Instability (不稳定度)
* A: Abstractness (抽象度)
应该保持偏差越小越好,即下图所示交点都落在绿色反比线左右:
基于上面的原则,HTTL的包结构整体上划分为三层:(对应上面类图中的三列)
* API (Application Programming Interface)
* 模板引擎的使用者依赖的接口类,也是核心领域模型所在,保持最少概念,并隐藏实现细节,其中Engine类相当于微内核,只管理非功能性的扩展点的加载,不硬编码模板加载解析渲染的任何部分。
* SPI (Service Provider Interface)
* 模板引擎的扩展者依赖的接口类,它依赖于API的领域模型,它是模板引擎功能正交分解的抽象层,以保证用户可以最小粒度替换需要改写的地方,方便二次开发。
* BUILT-IN (Built-in Implementation)
* 内置扩展实现,它是SPI标准实现,也是可被用户替换的类,它包含引擎所有做的事,包括扩展点之间的组装过程(可替换DefaultEngine),以确保没有功能换不掉,即平等对待扩展者。
采用子包依赖父包风格,所以将API放在根目录,SPI接口独立子包,各种实现放在SPI的下一级子包中。
* 使用者API导入:import httl.*;
* 扩展者SPI导入:import httl.spi.*;
下图是HTTL所有包的不稳定度与抽象度的比值距阵:(下图为JDepend绘制)
HTTL所有核心包都是靠近反比线的,即上图中用绿色标识的点,表示分包是合理的。
注:图中黑色的点为util相关包,它们不抽象,却被很多包依赖,只是内部复用代码,不影响整体设计,用户请不要依赖HTTL的util类。
再来看一下扩展点的执行顺序,序列图如下:
如果你要看代码,可以从入口类Engine和DefaultEngine开始,按此调用过程跟踪。
查看大图
获取模板过程说明:(与上图中的序号对应)
1 当从引擎中获取模板时,
1.1 首先会在缓存查找是否已缓存,如果有缓存就直接返回,
1.2 如果没有,则加载模板,
1.3 接着进行模板语法解析,
1.3.1 在解析到表达式时,将其转译为Java表达式,
1.3.2 并对静态文本进行编译前过滤,比如删除空白等,
1.3.3 对解析后的Java代码进行编译,得到具体模板实现类,
1.3.4 实例化模板实现类,
1.4 将模板实例写入缓存,并返回给用户,
查看大图
渲染模板过程说明:(与上图中的序号对应)
1 当用户调用模板的渲染方法时,
1.1 将非Map变量对象转换成Map,将非Writer或OutputStream输出对象转成Writer或OutputStream,
1.2 将变量Map压入Context栈,
1.3 如果有拦截器,将实际渲染过程封装成Listener,传给拦截器执行,
1.3.1 拦截器执行完拦截逻辑后,调用拦截时传入的Listener,
1.3.1.1 该Listener回调模板的doRender方法,执行实际渲染过程,
1.4 模板中的变量,均从Context中读取,
1.4.1 如果当前Context不存在,则向上一级Context中读取,
1.4.1.1 如果已经是根级别Context,则向Resolver读取,
1.5 模板输出变量时,先通过Formatter,将值对象转成String,
1.6 再通过Filter,过虑输出String的XML特殊符等,
1.7 最终,将过滤后的String输出,
1.8 模板渲染结束后,将当前Conetext弹出。
test
gggg test
test
启动时会打印热加载目录日志,有可能你改错了模板的位置,比如在Eclipse运行,实现上热加载的是wtp的临时目录,而不src/main/webapp目录,如果需要指定目录,可以用FileLoader。
参见:
http://httl.github.io/zh/help.html#出现改模板后不能生效怎么办?
当然可以。
你可以配置:
cache=null
cache=null
import.packages=java.util,com.googlecode.httl
#parser=com.googlecode.httl.support.parsers.AttributeParser
#compiler=com.googlecode.httl.support.compilers.JavassistCompiler
参照http://code.google.com/p/httl/后配置
httl.properties文件如上。还是不行。
你可以配置:
cache=null
让你见笑了。。
昨天才刚开始用httl,都没有去好好地看文档,呃,好吧,文档都还没下载。。。
你可以配置:
cache=null
HTTL源代码参见:https://github.com/httl/httl/
先来看一下HTTL的类结构设计,类图如下:
查看大图
模型划分原则:按实体域,服务域,会话域划分。
不管你做一个什么产品,都一定有一个被操作的主体,比如:服务框架管理的Service,任务框架管理的Task,Spring管理的Bean等,这就是实体域。
即然有被操作者,就一定有操作者,它管理被操作者的生命周期,发起动作,比如:服务框架的ServiceInvoker,,任务框架的TaskScheduler,Spring的BeanFactory等,这就是服务域。
服务域发起动作,在执行过程中,会有一些临时状态需要存储交换,比如:Invacation,Execution,Request等,这就是会话域。
相应的,在HTTL中:
* Engine 为服务域
* 它是API的入口,并负责实体域Template的生命周期管理,它是Singleton单一实例的,加载后不可变,所以是线程安全的,它的初始化过程较重,请复用单例。
* Template 为实体域
* 代表着被操作者,它是Prototype原型实例的,即每个模板产生一个实例,加载后不可变,同样也是线程安全的,模板变化后,将产生不同的实例,而不改变原实例。
* Context 为会话域
* 持有操作过程中的所有可变状态,它是ThreadLocal线程内实例的,即不和其它线程竞争使用,所以也是线程安全的,请不要跨线程传递,它的初始化过程很轻量,每次模板执行前都新建实例,执行完即销毁。
这样划分的好处是,职责清晰,可变状态集中,每个域都是无锁线程安全的,保证在大并发下,不会降低系统的活性。
这些核心领域模型也就是HTTL的API(Application Programming Interface),它是HTTL暴露给用户的最少概念,也就是上面类图中的第一列。
扩展点组装原则:按“微核+插件”体系组装。
但凡有生命力的产品,都是在扩展性方面设计的比较好的,因为没有哪个产品可以覆盖所有需求,对于开源软件尤其如此。
所以,产品只有具有良好的扩展性,允许用户或第三方参与进来,进行二次开发,才能保持生命力。
怎么样的扩展性才是最好的?通常来讲,就是没有任何功能是硬编码的,所有的功能都可被用户替换。
那要如何才能做到这样?一个重要的原则就是:平等对待第三方。
也就是凡是原作者能实现的功能,第三方也要能够在不改变源代码的前提下实现。
换言之,原作者应把自己也当作扩展者,自己添加功能时,也要用第三方扩展者同样的方式进行,而不要有特权。
要做到这一点,就需要一个良好的框架支撑,“微核+插件”是一个不错的选择,Eclipse, Maven等知名软件都采用该体系。
什么是“微核+插件”?微核,即最小化核心,内核只负责插件的组装,不带任何功能逻辑,所有功能都由可替换的插件实现,
并且,组装过程应基于统一的规则,比如基于setter注入,而不能对不同插件硬编码组装,这样可以确保没有任何功能在内核中硬编码。
比如:Spring, OSGI, JMX, ServiceLoader等都是常见的微核容器,它们负责基于统一规则的组装,但不带功能逻辑。
当然,如果你不想带这么重的框架,也可以自行实现,HTTL就采用自行实现的httl.util.BeanFactory作为组装微核。
在Engine.getEngine()中调用了BeanFatory.createBean(Engine.class, properties),
其中,properties即为httl.properties配置,BeanFatory基于setter方法,递归注入所有对象的属性。
比如:httl.properties中配置了parser=httl.spi.parsers.CommentParser,
而DefaultEngine中有setParser(Parser parser)方法,就会被注入,并且Parser本身的属性也会递归注入。
既然非功能性的插件组装过程,可以由微核框架来完成,那功能性的组装怎么办呢?
我们应该把功能性的组装过程也封装成插件,即让大插件组装小插件,形成级联组装关系。
比如,HTTL的入口类Engine的实例也是一个插件,它负责模板的缓存,加载,解析的总调度,即你可以替换DefaultEngine实现。
只需在httl.properties中配置:engine=com.your.YourEngine,可以将现有Parser等SPI注入你的Engine。
这些插件的接口,也就是HTTL的SPI(Service Provider Interface),它是HTTL暴露给扩展者的最小粒度的替换单元,也就是上面类图中的第二列。
分包原则:按复用度,抽象度,稳定度分包。
* 复用度:
* 每种用户所需用到的类,就是同一复用粒度的,比如:使用者和扩展者,这样可以减少代码干扰,以及最大化复用。
* 稳定度:
* 被依赖包和依赖包的占比,如果一个包依赖很多包,那别的包变化都会引起它跟随变化,所以它就不稳定,反之即稳定,
保持被依赖者总是比依赖者的稳定度高,形成金子塔关系,这样可以防止不稳定性传染,比如a包只依赖3个包,而b包依赖10个包,那就不要让a包去依赖b包。
* 抽象度:
* 包中抽象类个数占比,比如包中有10个类,其中3个为抽象类(包括接口),则抽象度为3/10,
保持包的稳定度和抽象度成正比,即把抽象类(包括接口)放到稳定的包中,把具体实现类放到不稳定的包中,这样可以保持每层都有足够的扩展性。
稳定度与抽象度关系如下图:
也就是分包应该如下:
其中上面那个包不依赖其它包。所以它很稳定,应尽量把抽象类或接口放在这一层,
而下面那个包依赖了三个包,三个包变化都会引起它跟随变化,所以它是不稳定的,应尽量把具体实现类放在这一层。
因稳定度与抽象度成正比,所以不稳定度与抽象度成反比,用反比方便画图,计算方式如下:
* (1) I = Ce / (Ca + Ce)
* I: Instability (不稳定度)
* Ca: Afferent Coupling (传入依赖,也就是被其它包依赖的个数)
* Ce: Efferent Coupling (输出依赖,也就是依赖其它包的个数)
* (2) A = Na / Nc
* A: Abstractness (抽象度)
* Na: Number of abstract classes (抽象类的个数)
* Nc: Number of classes (类的个数,包括抽象类)
* (3) D = abs(1 - I - A) * sin(45)
* D: Distance (偏差)
* I: Instability (不稳定度)
* A: Abstractness (抽象度)
应该保持偏差越小越好,即下图所示交点都落在绿色反比线左右:
基于上面的原则,HTTL的包结构整体上划分为三层:(对应上面类图中的三列)
* API (Application Programming Interface)
* 模板引擎的使用者依赖的接口类,也是核心领域模型所在,保持最少概念,并隐藏实现细节,其中Engine类相当于微内核,只管理非功能性的扩展点的加载,不硬编码模板加载解析渲染的任何部分。
* SPI (Service Provider Interface)
* 模板引擎的扩展者依赖的接口类,它依赖于API的领域模型,它是模板引擎功能正交分解的抽象层,以保证用户可以最小粒度替换需要改写的地方,方便二次开发。
* BUILT-IN (Built-in Implementation)
* 内置扩展实现,它是SPI标准实现,也是可被用户替换的类,它包含引擎所有做的事,包括扩展点之间的组装过程(可替换DefaultEngine),以确保没有功能换不掉,即平等对待扩展者。
采用子包依赖父包风格,所以将API放在根目录,SPI接口独立子包,各种实现放在SPI的下一级子包中。
* 使用者API导入:import httl.*;
* 扩展者SPI导入:import httl.spi.*;
下图是HTTL所有包的不稳定度与抽象度的比值距阵:(下图为JDepend绘制)
HTTL所有核心包都是靠近反比线的,即上图中用绿色标识的点,表示分包是合理的。
注:图中黑色的点为util相关包,它们不抽象,却被很多包依赖,只是内部复用代码,不影响整体设计,用户请不要依赖HTTL的util类。
再来看一下扩展点的执行顺序,序列图如下:
如果你要看代码,可以从入口类Engine和DefaultEngine开始,按此调用过程跟踪。
查看大图
获取模板过程说明:(与上图中的序号对应)
1 当从引擎中获取模板时,
1.1 首先会在缓存查找是否已缓存,如果有缓存就直接返回,
1.2 如果没有,则加载模板,
1.3 接着进行模板语法解析,
1.3.1 在解析到表达式时,将其转译为Java表达式,
1.3.2 并对静态文本进行编译前过滤,比如删除空白等,
1.3.3 对解析后的Java代码进行编译,得到具体模板实现类,
1.3.4 实例化模板实现类,
1.4 将模板实例写入缓存,并返回给用户,
查看大图
渲染模板过程说明:(与上图中的序号对应)
1 当用户调用模板的渲染方法时,
1.1 将非Map变量对象转换成Map,将非Writer或OutputStream输出对象转成Writer或OutputStream,
1.2 将变量Map压入Context栈,
1.3 如果有拦截器,将实际渲染过程封装成Listener,传给拦截器执行,
1.3.1 拦截器执行完拦截逻辑后,调用拦截时传入的Listener,
1.3.1.1 该Listener回调模板的doRender方法,执行实际渲染过程,
1.4 模板中的变量,均从Context中读取,
1.4.1 如果当前Context不存在,则向上一级Context中读取,
1.4.1.1 如果已经是根级别Context,则向Resolver读取,
1.5 模板输出变量时,先通过Formatter,将值对象转成String,
1.6 再通过Filter,过虑输出String的XML特殊符等,
1.7 最终,将过滤后的String输出,
1.8 模板渲染结束后,将当前Conetext弹出。
评论
18 楼
ghsau
2017-11-03
将自己写代码的感悟总结成行之有效的理论,再拿这套理论去审视自己的代码,理论与实践结合,大神级人物,佩服!
17 楼
semmy
2014-08-26
Spring MVC 返回的JSON 在httl如何处理
16 楼
dpcheung
2014-04-10
有生成静态html的示例吗
15 楼
flyingfish飞鱼翔天
2014-02-06
flyingfish飞鱼翔天 写道
wangfeiok222 写道
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
test
gggg test
14 楼
flyingfish飞鱼翔天
2014-02-06
wangfeiok222 写道
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
test
13 楼
javatar
2013-08-30
wangfeiok222 写道
热加载不用重启,但是不起作用,配置如下,谁知道怎么搞的
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
启动时会打印热加载目录日志,有可能你改错了模板的位置,比如在Eclipse运行,实现上热加载的是wtp的临时目录,而不src/main/webapp目录,如果需要指定目录,可以用FileLoader。
参见:
http://httl.github.io/zh/help.html#出现改模板后不能生效怎么办?
12 楼
javatar
2013-08-30
semmy 写道
这个可以生成静态html页面吗
当然可以。
11 楼
semmy
2013-08-27
这个可以生成静态html页面吗
10 楼
wangfeiok222
2013-07-31
热加载不用重启,但是不起作用,配置如下,谁知道怎么搞的
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
9 楼
wangfeiok222
2013-07-31
reloadable=true
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
precompiled=false
compiler=httl.spi.compilers.JavassistCompiler
8 楼
jinceon
2012-04-10
我错了,这次我真的确定我知道怎么回事了。。打扰了。。。
7 楼
jinceon
2012-04-10
javatar 写道
jinceon 写道
能不能考虑多写个方法,允许开发时忽略缓存,强制从文件解析??
你可以配置:
cache=null
cache=null
import.packages=java.util,com.googlecode.httl
#parser=com.googlecode.httl.support.parsers.AttributeParser
#compiler=com.googlecode.httl.support.compilers.JavassistCompiler
参照http://code.google.com/p/httl/后配置
httl.properties文件如上。还是不行。
6 楼
jinceon
2012-04-10
javatar 写道
jinceon 写道
能不能考虑多写个方法,允许开发时忽略缓存,强制从文件解析??
你可以配置:
cache=null
让你见笑了。。
昨天才刚开始用httl,都没有去好好地看文档,呃,好吧,文档都还没下载。。。
5 楼
javatar
2012-04-10
jinceon 写道
能不能考虑多写个方法,允许开发时忽略缓存,强制从文件解析??
你可以配置:
cache=null
4 楼
jinceon
2012-04-10
能不能考虑多写个方法,允许开发时忽略缓存,强制从文件解析??
刚敲错字了
刚敲错字了
3 楼
jinceon
2012-04-10
梁大大,engine.getTemplate(String name)
能不能考虑多写个方法,运行开发时忽略缓存,强制从文件解析??
engine.getTemplate(String name,boolean ignoreCache)
在开发阶段,我想随时修改我的模板来调试。
由于有缓存,修改不立即生效,我只能重新启动tomcat。。。
能不能考虑多写个方法,运行开发时忽略缓存,强制从文件解析??
Template template = (Template) cache.get(name); if (template == null || (resource != null && resource.getLastModified() > template.getLastModified())) { lock.lock(); try { template = (Template) cache.get(name); // double check if (template == null || (resource != null && resource.getLastModified() > template.getLastModified())) { template = parseTemplate(name, encoding); cache.put(name, template); } } finally { lock.unlock(); } }
engine.getTemplate(String name,boolean ignoreCache)
在开发阶段,我想随时修改我的模板来调试。
由于有缓存,修改不立即生效,我只能重新启动tomcat。。。
2 楼
lqixv
2011-12-15
好像有两个月没更新了。还打算继续吗?一直在关注呢
1 楼
andongoop
2011-11-06
下载了你写的HTTL看了你的代码写的真不错,比自己高很多很多,非常的羡慕啊!
我是先看的你的代码,现在有看了你的设计思路与结构图,非常佩服。
我是先看的你的代码,现在有看了你的设计思路与结构图,非常佩服。
发表评论
-
能力成长模型
2012-05-09 00:28 23013最近看了温伯格1986年出版的《技术领导之路》, 很老的书,讲 ... -
使用Map参数的Webx3扩展
2011-08-28 02:10 5934因Webx3是开源的,所以把这个简单的Webx3扩展发在博客上 ... -
Netty内存泄露
2011-08-02 20:09 24979转于自己在公司的Blog: ... -
Grizzly和Netty以及Mina简单性能对比
2011-07-17 02:48 29765转于自己在公司的Blog: http://pt.alibaba ... -
RPC框架几行代码就够了
2011-07-14 00:34 90283转于自己在公司的Blog: http://pt.alibaba ... -
魔鬼在细节中
2011-05-24 14:50 32255转于自己在公司的Blog: ... -
Dubbo扩展点重构
2011-05-12 22:09 38910转于自己在公司的Blog: http://pt.alibaba ... -
配置设计
2011-03-09 23:41 23610转于自己在公司的Blog: ... -
[转]HTML5设计原理
2011-03-09 22:57 7839Jeremy Keith在 Fronteers 2010 ... -
Hessian序列化不设SerializerFactory性能问题
2010-12-27 11:38 6490转于自己在公司的Blog: http://pt.alibaba ... -
动态代理方案性能对比
2010-11-17 21:38 46249转于自己在公司的Blog: http://pt.alibaba ... -
防痴呆设计
2010-11-05 18:58 17701转于自己在公司的Blog: ... -
负载均衡扩展接口重构
2010-11-05 18:53 8767转于自己在公司的Blog: ... -
分布式服务框架常被质疑的价值
2010-11-05 18:52 5743转于自己在公司的Blog: http://pt.alibaba ... -
Hessian3.2.1在序列化32.5k字符串时的问题
2010-11-05 18:49 7288转于自己在公司的Blog: http://pt.alibaba ... -
一些设计上的基本常识
2010-07-05 19:28 27803转于自己在公司的Blog: ... -
谈谈扩充式扩展与增量式扩展
2010-06-12 19:46 19427转于自己在公司的Blog: http://pt.alibaba ... -
Scaling Architecture
2010-02-25 10:31 4129Scaling Second Life: http://p ... -
EBay SOA
2010-02-23 18:23 4811EBay SOA PPT -
服务化基础设施
2009-11-15 23:11 6290服务化,也可以叫SOA, ...
相关推荐
- **快速高效**:HTTL设计时考虑了性能,它的编译模型使得模板在运行前被编译为Java字节码,执行效率高。 - **简洁语法**:HTTL使用类似于JavaScript的表达式语法,如 `${var}` 表示变量,`@tag` 表示标签,易于...
HTTL模板引擎源码 HTTL(Hyper-Text Template Language)是一个高性能的JAVA开源模板引擎,适用于动态HTML页面输出,可替代JSP页面,它的指令和Velocity相似。
超文本模板语言( HTTL )和引擎 文献资料网页:|示例:|用户指南语法:|配置:|开发指南整合:英文|中文设计:英文|中文帮助(常见问题/团队成员):英语|中文 下载https://github.com/httl/httl/tags 或克隆项目...
自己学习用的,基本上采用都是最新版的程序,jre7编译 不建议直接导入,自己新建maven项目,然后一步步的导入文件,这样有利于学习 1分只是象征,如果一分都没有 ...互相学习,互相进步吧!">自己学习用的,基本上采用...
本篇文章将对四个流行的Java模板引擎——Velocity、FreeMarker、Smarty4j以及HTTL进行效率分析,旨在探讨它们在处理业务逻辑编译和性能方面的优劣。 1. Velocity: Velocity是Apache软件基金会的一个开源项目,以其...
【魔塔游戏开发素材】是一份集合了用于创建魔塔游戏的重要资源,为开发者提供了丰富的素材,便于构建属于自己的魔塔冒险世界。魔塔是一种基于数字逻辑和策略的像素风格游戏,深受玩家喜爱。这份素材可能包括角色图像...
RGB还能扩展到RGBA,添加一个Alpha通道来控制颜色的透明度,如 RGBA(255, 0, 0, 0.5) 将创建半透明的红色。 再来看HSL(Hue, Saturation, Lightness)和HSLA颜色模型。HSL模型基于色相(角度,0-360度)、饱和度...
该系统利用先进的J2EE技术,结合多种框架和工具,以提升效率,减轻管理人员工作负担,保障信息安全性,同时也具备良好的扩展性和健壮性。 系统的核心架构采用了Spring、Struts2和MyBatis三大框架。Spring作为企业级...
以NPN型三极管为例,当输入电压Vi为0V时,三极管截止,输出Vo为高电平(3V)。当Vi升至3V,三极管饱和,输出Vo变为低电平(0.1~0.3V)。这种非门电路通过调整基极电阻R1和R2,可以控制三极管的工作状态,从而实现...
T4模板使用及CSHTMLT4模板使用及CSHTML
以六管单元的TTL与非门为例,其内部结构和工作原理被详细讲解。与非门的工作状态通常分为高电平和低电平两种情况。当输入信号中至少有一个为低电平时,电路会通过晶体管的饱和和截止状态确保输出为高电平;相反,当...
JSP》(中文版)结合SCWCD考试大纲讲述了关于如何编写servlets和JSP代码,如何使用JSP表达式语言,如何部署Web应用,如何开发定制标记,以及会话状态、包装器、过滤器、企业设计模式等方面的知识,以一种轻松、幽默而...
JSP》(中文版)结合SCWCD考试大纲讲述了关于如何编写servlets和JSP代码,如何使用JSP表达式语言,如何部署Web应用,如何开发定制标记,以及会话状态、包装器、过滤器、企业设计模式等方面的知识,以一种轻松、幽默而...
JSP》(中文版)结合SCWCD考试大纲讲述了关于如何编写servlets和JSP代码,如何使用JSP表达式语言,如何部署Web应用,如何开发定制标记,以及会话状态、包装器、过滤器、企业设计模式等方面的知识,以一种轻松、幽默而...
JSP》(中文版)结合SCWCD考试大纲讲述了关于如何编写servlets和JSP代码,如何使用JSP表达式语言,如何部署Web应用,如何开发定制标记,以及会话状态、包装器、过滤器、企业设计模式等方面的知识,以一种轻松、幽默而...
5. **安全性考虑**:文件上传时要防止恶意文件如病毒或脚本文件,通常需要限制文件类型和大小,对文件名进行重命名以避免覆盖现有文件。下载时,要确保只允许访问指定的、安全的文件路径,防止路径遍历攻击。 6. **...
它们的主要区别在于TTL电路以双极型晶体管为基础,而COMS电路则采用了互补金属氧化物半导体晶体管。TTL电路以其高速性能著称,但功耗相对较高;而COMS电路虽然速度稍慢,却拥有更低的功耗,这使得COMS在便携式电子...
再者,文档中提到了电路上的一些基本知识,如电路系列的缩写符号,如TTL(晶体管-晶体管逻辑)、HTTL(高速TTL)、CMOS(互补金属氧化物半导体)等,这些都是集成电路领域常见的逻辑门类型。TTL系列包括不同速度和...