当前位置: 首页 > 工具软件 > SpringSide > 使用案例 >

SpringSide实战(一)----SpringSide简介

商俊智
2023-12-01

最近在公司用JUP框架做项目,发现这个框架是别人基于SpringSide封装的,所以打算学习下,SpringSide,其中遇到了很多坑,做个记录,网上关于这方面的资料都有些老了,而且SpringSide最新的版本是SpringSide-Utils,老一点的版本为v4.2.2.GA,以下分别对这两个版本分别介绍下,主要内容来自于网上。


一些资料:


Github源码地址:  https://github.com/springside/springside4

OSchina源码地址: https://git.oschina.net/calvin1978/springside4

官方文档:  https://github.com/springside/springside4/wiki

SpringSide网址: http://springside.github.io/


1、SpringSide简介


SpringSide--Pragmatic Enterprise Application KickStart and Common Library Stack,这么长的一个名字下来,不用解释大家都知道是做什么的了----以Spring Framework为core,提供一个Pragmatic的企业应用开发基础以及企业应用中各主题的最佳实践展示。 


愿景:为使用Spring框架的开发者提供一个非Demo版的复杂、正式而体现最佳使用实践的参照系统。为JavaEEer必须面对的问题提供合乎Pragmatic原则的解决方案。 


SpringSide的四个部分--
Springside-Bookstore:  一个Full Feature的书店示例,兼有书店前台和后台管理,作为典型企业应用的微缩版。 
SpringSide-Core :SpringSide封装的核心代码。  
SpringSide-Templates: 让用户可以快速复制粘贴构建出自己应用的代码模版,分Application与Plugins两部分。 
SpringSide-Generator: 自动整合SpringSide-Application/Plugins生成项目,生成CRUD代码的Eclipse Plugins 和Ant 脚本。


来看看SpringSide的作者,江南白衣的对它的介绍:


SpringSide是什么?为什么要发起这个项目? 

SpringSide是以Spring Framework为核心的,Pragmatic风格的JavaEE应用参考示例,是Java世界中的主流技术选型,最佳实践的总结与演示。因为基于Spring也因为对Spring理念的认同,项目起名SpringSide,另外还有个好记的中文名字——“春天的旁边”。 

想起做这个项目,是在六七年前元旦辗转反侧的夜晚,想着自己应该为世界留下点什么。写一本书还是做一个开源项目呢? 总感觉书印出来了就没法改了,对我这种完美主义者有点难受。而开源项目,就可以永远年轻,永远生长,永远重构…… 

然后,做什么项目呢?那时候,淘宝们还没有开始大规模开源自己的技术。国内的原创框架更多是在自娱自乐。所以SprinSide选了一条更低端的路线,将那时候已经太多而不是太少的开源项目粘合在一起,用好,也算是一桩功德了。

SpringSide包含哪些演示项目? 这些项目采用或演示了哪些技术? 

SpringSide里含有QuickStart 与 Showcase 一小一大两个示例项目。 

QuickStart是一个迷你的TodoList应用,浓缩了一个普通JavaEE应用所需的柴米油盐各种基础技术,从典型的CRUD界面,到赶时髦的Rest API,以及最基础的用户管理功能,可以作为很多项目的初始骨架。 


Showcase 则一个五花八门的JavaEE技术大杂烩大派对,如安全、缓存、日志、消息中间件、定时任务等等等等。


SpringSide 4和之前版本相比,有哪些较大改进?
 


SSH 与 SSH2 发展到高潮后,Spring也进入了一个后Spring的时代,受到各种新兴语言与框架如Play! Framework的围攻。SpringSide 4,演示的就是这个后Spring时代的演进,如何使得avaEE依然是个体面的选择。 

一些变动包括 DAO框架转用Spring Data JPA + Hibernate, MVC框架转用Spring MVC 3, Restful框架转用Spring MVC + Spring RestTemplate, CSS框架转用Twitter Bootstrap,安全框架转用Apache Shiro 等等,Selenium升级到WebDriver。 


所有变动的目标,都是在代码越来越简单的同时,也保持对工业化大规模开发的支持。比如有些新兴语言框架,高手自己可以写得很快,但不一定适合很多普通程序员一起合作开发与维护。所以有些过度简化的演进,比如完全抛弃XML纯用Annotation的ApplicationContext定义方式,SpringSide并没有使用。


如何基于SpringSide创建新的项目?
 

SpringSide也是利用Maven的Archetype插件来创建新项目的,在每次版本发布时都会把前面所说的QuickStart项目打包成一个模板项目。用户只要用标准的maven archetype指令,就可以基于QuickStart项目生成自己的项目。

SpringSide采用什么开源协议?对商用有什么限制? 

用的是所知最开放的Apache License2,任何的Copy&Paste都是欢迎的。如果有哪个更开放的告诉我吧,因为实在对靠开源赚钱没有过任何想法。

有没有其他开发者参与贡献? 

4.0这个大版本暂时只有我一个在主导。不过github真的是一个非常社交化的开源平台,没有了sourceforge、google code那种固定的开发团队的概念。现在谁都可以闯进SpringSide来,改它几行代码,然后向我发起一个Pull Request就可以了。题外话,像Nutz那样精细的贡献者记录,真是值得表扬又让人羡慕的事情。


SpringSide的发布周期?未来的发展方向?
 


项目坚持了六七年,四个大版本,期间服务器迁徙数次,也有过多次跳票的不良记录。所以很难说出一个固定的发布周期来。最近自己比较希望能做到与白天的项目一样,固定三周一个的迭代,但也并不总能如愿。希望大家能相信我的人品,项目或迟或早,总是会发布的…… 

至于未来的发展方向,一方面会继续做细JavaEE普通应用的演示,使它与一般的玩具型演示项目有更显眼的区别。一方面会展示更多互联网项目的新潮技术,如NoSQL、ZooKeeper等,毕竟这看起来更有趣。


2、SpringSide4技术选型


1. Web

MVC Framwork: SpringMVC3.0 Restful的风格终于回归了MVC框架的简单本质,对比之下Struts2概念太复杂更新又太懒了。

Template:JSP2.0且尽量使用JSP EL而不是taglib,万一要写taglib也用纯JSP来编写,一向是SpringSide的推荐,Freemarker们始终有点小众, 而Thymeleaf与美工配合度非常高,可惜也是太少用户了。

Layout Decoration: Tiles的配置都太复杂了,SiteMesh2好些,但Sitemesh3烂尾了。

JavaScript Library: 随大流用了JQuery。其实Dojo的面向对象语法更优美,但用户数和插件社区差了点。

CSS Framework: 最热火的Twitter Bootstrap,提供了简便的布局能力和基本的页面美化。

JavaScript/CSS Compressor: 还是随便选的YUI Compressor

ValidationJQuery Validation Plugin这种客户端校验的客户体验更好,而spring MVC集成hibernateValiator的服务端校验则可以避免恶意用户跳过页面直接发送请求,校验规则也更多,需要混合使用。


2. WebService

SOAP WebService: JAX-WS2.0的注解 + Apache CXF 无疑是最成熟的,一说起Axis1/2我都要打冷颤。

Restful Service: JAX-RS 1.0 + Jersey/CXF,够标准。但直接使用Spring MVC能使架构更简单。 如果追求极致的性能标,直接写Servlet也没啥。

Restful Client: 刚出来的JAX-RS 2.0标准,实际是用Jersey的client api做蓝本的, 而直接使用Spring的RestTemplate可以减少第三方包的引入。

为了隔绝变化影响,隐藏细节,对外暴露的DTO和应用内部的领域对象是不同的类型,用Dozer进行复制。

请求参数的校验,JSR303 Bean Validator的实现Hibernate Validator没太多的竞争对手。


3. Database

数据库设计基本原则: 见DataBase的相关章节

ORM Framework: 快速开发的应用里,领域对象肯定是用JPA标注的。至于API用Hibernate还是JPA,因为那个极简便的,DAO只要写接口就好了的Spring-Data-JPA,所以选了JPA。 当然,JPA的实现还是用Hibernate

追求高性能的应用,如各种Web服务,当然就是MyBatis了。如果项目再简单点,Spring JDBC其实也不错。

传统数据库: 无非OracleMySQL的选择,如果你恨MySQL依然是Oracle家的东西,可以考虑越来越多人用的,语法和Oracle很像的Postgresql。

NOSQL数据库: 国内用的比较多的还是RedisMongoDBRedis更像一个数据结构服务器,暴露各种数据结构的专有API。而MongoDB将数据存成BSON格式,也提供类似SQL的查询语句,更像一个schema-less的数据库。

数据库连接池: Apache DBCP本来一统江湖,现在被人批评又慢又复杂,所以有了Tomcat JDBC,另外温少的Druid也是一个选择。

Cache: 在JVM里的缓存,最老牌最多人用的依然是Ehcache,一些更强大的DataGrid方案如HazelCast,JBoss的Infinispan反而没什么人用。另外最简单的JVM内缓存是Guava的Cache

而中央式的缓存,Memcached已经成为了事实标准。而且当主创撒手不管后,社区现在反而有着稳定的更新。 Client方面,比较稳健选择的还是Spymemcached


3. Services

Security Framework: 选择Apache Shiro是因为SpringSecurity的代码复杂度已经超过了它的实际需要,扩展困难痛苦。另一个原因是SpringSecurity的基本API居然只支持基于角色的判断,e.g. hasRole("Administrator"),而Shiro同时还支持我们其实更常用的基于Permission的判断,e.g. hasPermission("User:Edit")。

JMS: ActiveMQ是最多人选用的应用服务器无关的JMS实现,JBoss的HornetQ同样只是JBoss的用户在使用。Spring自带的JMS封装很好用。但还有更高级的如支持跨平台的AMQP协议的RabbmitMQ。

Schedule: 对于固定时间间隔的任务,JDK自带的Executor已足够好。Cron式定时执行,Spring的Scheduler也能满足。而且Spring的提供的纯XML配置也让Scheduler变得很简单,Quartz更大的优势体现在保证集群中有且仅有一台服务器执行任务。另外,SpringSide还演示了基于Redis做了一个适合海量的只需单次触发的任务。

JMXJolokia能将JMX中的MBean以Restful+JSON的方式暴露出来,使JMX这个古老的,在平台互通中显得有点封闭的协议重新焕发了青春。而Spring-Jmx将普通POJO注释一下就变成MBean也非常方便。

其他Production Feature: 用Hystrix对访问资源进行并发、延时、短路控制,防止系统雪崩。而监控方便包括自己写的Metrics ReporterGraphite


4. Utilizes

General: Apache Commons Lang说是伴着我们长大的也不为过,3.0版连package名也改了,全面支持泛型。 Guava 是Google新鲜推出的优雅产品。但说它会一桶天下又不定,因为它有时候太新潮了,反而用不惯。比如StringUtils我还是喜欢用Apache的,IO也同样是Apache Commons IO的好使。

XML: 用JDK自带的JAXB就算了,不折腾。

JSON: GSon虽然系出名门而且接口优雅,但Jackson的功能更加丰富到匪夷所思,而且比GSon快很多。

Email: Spring自带的Email封装挺好用的。

LoggingSlf4j作为入口,早就替代了Apache Common Logging了,下面的实现Log4j 1.x 被批判太多同步方法太慢,Log4j作者的后作Logback就好很多了,但社区似乎不甘心log在一家QOS公司手里,又在推动log4j2.0的发展,目前还是beta版。另外选择Logstash做日志的中央式处理。

最后,Freemarker虽然不用来做页面Template,平时用来生成点东西也不错的。 JodaTime这种要直接加入JDK的就不多说它了。HttpClient建议用Apache HttpClient好过JDK自带。


5. Test

Unit Test: JUnit始终是正统,TestNG的功能如测试用例分组它也慢慢支持了。AssertJ 是目前最好的Assert语句库。

Mock: Mockito的API比老牌的EasyMock更为优雅,而PowerMock则能配合Mockito完成static方法,函数内部new 出来的对象这些Mockito做不了的mock。

Functional TestSelenium与WebDriver的合并后,最大改进是原来基于javascript的方案, 变成了直接调用浏览器的核心API,性能好了。

Performance/Stability Test: [Jmeter]作为测试工具是最成熟的,Gatling还需要时间成熟。


6. Development Environment

JDK6这样没什么兼容性问题又成熟得一塌糊涂的版本建议大家都升级吧。JDK7也不错,有G1垃圾收集器和Try-Catch新语法的语法糖。

Jetty7是因为它的嵌入式版本做得好,集成测试不用部署直接就开跑了。开发时一般也不用Eclipse插件,直接自己在代码里启动了,省下打包拷贝War文件的时间。Tomcat现在也有嵌入式版本了,而Jetty最新版要JDK7。

H2 Database,既是嵌入式的,又可以持久化到文件用Web Console查看,性能还是嵌入式中最好的。

Maven,在项目构建脚本不复杂的时候的首选,否则就只能ant+ivy了,或者像hibernate和spring一样,用gradle.

另外,用Log4jdbc在开发时查看实际执行的SQL。

最后,用Jenkins做持续集成, Sonar做代码质量检查,是大部分好项目的共同爱好。



以下是对SpringSide-Utils的一个简单介绍:


1.SpringSide-Utils简介


把在唯品会两年的实践抽取出来,做一个大大大的公共类库。一边封装 Guava 和 Apache Common Lang,一边参考移植各门各派的精华:


框架/容器随身自带:Spring,Netty,Tomcat,Jetty,ElasticSearch

专门的类库:Jodd,  Apache Common IO,Common Collections,JCTool,OpenHFT,AndroidUtilCode

大厂的开源类库:Facebook JCommon,twitter commons,linkedin-utils


内库中包含了文本、数字、日期、并发、集合、文件、反射、安全等方面的内容等着大家一一探索,这里又再唠叨一下性能,性能,性能。

新库的设计目标,是把最佳实践都封装起来,让大家使用类库时,默认就获得最优的性能。


2.日期

2.1 DateFormatUtil

日期与String相互转换时,JDK的SimpleDateFormat,又慢,又非线程安全。

在不能全面转为Joda Time时,使用Common Lang的FastDateFormat,又快,又线程安全,还能缓存实例。

2.2 CachingDateFormatter

FastDateFormat再快,日期格式化还是个消耗很大的事情。

参考Logback和Log4j2,在打印当前时间的场景里,将同一时刻的结果缓存。


3. 文本

3.1 StringBuilderHolder

ThreadLocal地重用StringBuilder,节约长字符串拼接时的内存消耗,节约成倍复制扩容的CPU消耗,是OpenHFT等好几个类库的共同选择。

3.2 HashUtil

ThreadLocal地重用SHA1的MessageDiggest,减少每次创建MessageDigest的消耗,也是Tomcat,Facebook等好几个类库的共同选择。

3.3 JsonMapper

封装Jackson的实现,并提供不序列化“值为NULL的属性”等选择。

3.4 TextValidator

判断是否合法的电话,身份证之类的正则表达式校验,Pattern必须得预先编译而不要每次创建,但总有匆忙的同学忘记这点。

3.5 MoreStringUtil

Common Lang的StringUtils已经很好用了。不过字符串操作的消耗总是很大,这里针对一些操作,给出更极致的性能优化,比如split()。


4. 集合

4.1 原子类型集合

当集合中的元素是原子类型,而不是对象的时候。直接以原子类型来存储,不但节约内存(int vs Integer, 4 bytes vs 16 bytes),甚至内部的数据结构也能完全不一样,从而大幅提高性能。

从Netty中移植了IntOjbectHashMap 和 LongObjectHashMap,性能约提升50%。后面还会有IntArrayList等等。


4.2  MapUtil, ListUtil ...


各种集合类的Util的创建函数,强迫大家去思考Array Base 集合类的初始大小,避免了容量不足时的成倍扩容; HashMap的加载因子,减少哈希冲突。


在集合为空或只有一个元素时,使用Java Collections的特殊数据结构,进一步节约内存。


4.3 其他扩展类型


1. Guava


MuitlSet :as MapCounter,不用再自己处理“如果有就+1,没有就放个元素进去”的烦事


MultiMap: as MultiValueMap


WeakConcurrentHashMap: 键值为弱引用的并发Map,只此一家


RangeMap:定义一段范围的Key,对应一个Value,类似一致性哈希环之类的最合适


2. Common Collections:


UniqueArrayList


MultiKeyMap


Flat3Map:如果少于3个元素直接访问属性,否则才访问真正的HashMap


3. Jodd

SortedArrayList


4. JCTools


针对 “多个生产者一个消费者”, “一个生产者多个消费者” 等特定场景优化的Queue。


5. 并发


5.1 JSR166e


JDK的不同版本,不断推出性能更优的并发实现,但如果考虑多JDK版本到的兼容就让人发愁了。好在有Doug Lea大神的JSR166e项目。


1. ThreadLocalRandom


Random本身有全局锁,JDK7的ThreadLocalRandom通过在ThreadLocal里放Random避免了锁。


2. LongAdder


作为计数器,AtomicLong虽然能通过CAS避免锁,但如果线程竞争激烈时依然有很大的损耗。JDK8的LongAdder,根据并发情况,将计数器智能的拆开成若干个,等取值时再求和。


3. ConcurrentHashMapV8


JDK5开始的ConcurrentHashMap是经典的分散锁模式,而JDK8的ConcurrentHashMap,优化后居然取消了锁。


5.2 ThreadPoolBuilder


比JDK Executors,提供更好的线程池设置,比如FixedPool的队列最大长度,CachedPool的最大线程数等。


另提供一个从Tomcat移植的QueueableCachedPool,“支持可变的线程数,跑满线程时任务放队列”这种符合大家想想的场景。


5.3 ThreadLocalContext


提供ThreadLocal HashMap存放上下文的示例,并给出更高效的,使用EnumMap的建议。


6. 反射

6.1 BeanMapper

基于orika封装,同时避免了一些低效API的使用,比如不给出来源集合的类型,让框架自己去反射"iterator"函数的返回值来获取类型的恶劣行为。

更给出了预生成Type类型的最高效的用法。


6.2 FastMethodInvoker

基于cglib,通过代码生成实现最快速的反射调用。比如反射调用A类的“hello” 方法,它就直接生成一个调用a.hello()的FastMethod子类.

7. 其他

7.1 ExceptionUtil

异常构造时,获取当前Stack Trace是一个很耗时的过程,把Stack Trace打印也同样消耗。

如果是一个比较清楚出处的异常,可以通过static定义的静态异常。

但如果异常的message会变化,就不能静态定义唯一的异常了,此时可使用克隆异常,依然避过构造函数。

7.2 SystemPropertiesUtil

Properties本质上是一个有锁的HashTable,所以不能频繁的调用System.getProperty()。提供了一个以回调方式获取变化的ListenableProperties。


 类似资料: