术语

快照版:开发过程中的不稳定版本,开发阶段使用

发布版:稳定的发行版本,测试、部署阶段使用

1.设置MAVEN_OPTS环境变量

当Maven项目很大,或者你运行诸如 mvn site 这样的命令的时候,maven运行需要很大的内存,在默认配置下,就可能遇到java的堆溢出,报OutOfMemoryError错误。解决的方法是调整java的堆大小的值。

Windows环境中:

找到文件%M2_HOME%\bin\mvn.bat ,这就是启动Maven的脚本文件,在该文件中你能看到有一行注释为:

  @REM set MAVEN_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE...

它的意思是你可以设置一些Maven参数,我们就在注释下面加入一行:

set MAVEN_OPTS= -Xms128m -Xmx512m

之后,当你运行Maven命令如: mvn -version 查看配置是否生效。

2.配置用户范围settings.xml

Maven用户可以选择配置$M2_HOME/conf/settings.xml或者${user.home}/.m2/settings.xml。前者是全局范围的,整台机器上的所有用户都会直接收到该配置的影响,而后者是用户范围的,只有当前用户才会收到该配置的影响。

我们推荐使用用户范围的settings.xml,主要是为了避免无意识地影响到系统中其他用户,当然,如果你有切实的需求,需要统一系统中所有用户的settings.xml配置,则当然应该使用全局范围的settings.xml。

3.不要使用IDE内嵌的Maven

不论是Eclipse还是NetBeas,当我们集成Maven的时候,都会安装上一个内嵌的Maven,如果即使用IDE的Maven,也使用命令行的Maven,这样由于版本不一致,容易造成构建行为的不一致,所以我们可以在IDE中配置Maven插件使用外部的Maven。

以下是Eclipse中选择这一个外部的Maven的方法。如下图:

eclipse配置外部maven

4.搭建本地仓库管理器

搭建本地仓库的好处:

1.通过为所有的来自中央Maven仓库的构件安装一个本地的缓存,你将加速组织内部的所有构建,所以通过本地仓库提供Maven依赖服务可以节省时间和带宽。

2.仓库管理器为组织提供了一种控制Maven下载的机制,你可以详细的设置从公开仓库包含或排除特定的构件。

3.Nexus的仓库可以管理项目的多个版本(快照版、发布版),方便了开发。

5.尽可能的遵循Maven的约定

maven规范

使用Maven的时候,你应该尽可能遵循它的配置约定,一方面可以简化配置,另一方面可建立起一种标准,减少交流学习成本。

其实基本上所有的约定,或者说默认配置,都可以在Maven的超级POM(super pom)中找到。由于所有的POM都继承了这个超级POM(类似于java中所有类都继承于Object),因此它的默认配置就被继承了。以Maven 2.0.9为例,你可以在%m2_home%/lib/下看到一个名为maven-2.0.9-uber.jar的文件,打开这个文件,可以找到org /apache/maven/project/pom-4.0.0.xml这个文件,这就是超级POM。

6.优先编译被依赖的模块

假设一个项目C有两个模块,模块A和模块B,其中模块A依赖模块B。若你直接编译项目C,Maven本应该先编译模块B,再编译模块A,因为模块A依赖模块B。但是不幸的是,Maven这方面支持的并不是那么完美。所以如果模块B有改动,我们应该先编译模块B,再编译整个项目C。希望Maven会在未来的版本中改进这个问题。

7.利用Maven插件创建项目

当我们需要创建一个基于Maven的项目时,我们可以有两种选择。一种是遵循Maven约定,自己创建项目需要的所有目录和文件(例如pom.xml),但是这种方式是不被推荐的。因为这种方式需要手动,而我们往往容易在不经意中犯下错误(例如拼写错误)。我们可以利用Maven的IDE插件(例如m2eclipse)创建一个基于Maven的项目,这种方式会自动生成Maven项目标准的目录和文件。

8.降低依赖重复

  • 上移共同的依赖至父pom.xml的<dependencyManagement>

如果多于一个项目依赖于一个特定的依赖,你可以在<dependencyManagement>中列出这个依赖。父POM包含一个版本和一组排除配置,所有的子POM需要使用<groupId>和<artifactId>引用这个依赖。如果依赖已经在<dependencyManagement>中列出,子项目可以忽略版本和排除配置。

  • 为兄弟项目使用内置的项目<version>和<groupId>

如果多个相关的依赖的版本都是相同的,可以使用properties元素定义Maven属性,依赖的版本值用这一属性引用表示。

<properties>
    <spring.groupId >org.springframework</spring.groupId>
    <spring.version>2.5.6</spring.version>
</properties>
<dependencies>
    <dependency>
        <groupId>${spring.groupId}</groupId>
        <artifactId>spring</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>${spring.groupId}</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

9.使用Maven Dependency插件进行优化

$ mvn dependency:analyze : 分析这个项目,查看是否有直接依赖(在pom.xml显式声明的依赖但没有被引用过),或者一些使用了但不是在pom.xml显式声明的依赖

$ mvn dependency:tree:列出项目中所有的直接和传递性依赖

通过以上两条命令来移除那些未使用,但声明的依赖,以及显示声明使用了,但未声明的依赖。

参考资料

  1. MAVEN使用最佳实践 闫国玉

  2. 好书:《Maven权威指南中文版》

Struts2的请求处理流程

  1. 客户端发送请求;
  2. 该请求经过一系列的过滤器(Filter):其中可选过滤器ActionContextCleanUp,帮助Struts2和其他框架集成。例如:SiteMesh Plugin。
  3. 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper,来决定该请求是否需要调用某个Action。
  4. 若ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
  5. ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类。
  6. ActionProxy创建一个ActionInvocation的实例。
  7. ActionInvocation实例调用Action的前后,涉及到相关拦截器(Intercepter)的调用。
  8. 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果是一个JSP或其他页面(也可以是其他的Action链)。 JSP页面展现可使用Struts2框架中的标签(该过程会涉及ActionMapper)。

struts2

SpringMVC的请求处理流程

  1. 客户端发送请求
  2. 请求被springmvc的DispatcherServlet前端控制器捕获
  3. 前端控制器对请求的URL进行解析得到请求资源标识符(URI),根据URI查找HandlerMapping获取该handler配置的所有相关的对象(包括Handler对象(Controller)及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回
  4. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
  5. DispatcherServlet通过HandlerAdapter执行handler(Controller),返回一个ModelAndView(包含了视图逻辑名与模型数据信息)交给DispatcherServlet
  6. DispatcherServlet根据返回的ModelAndView选择一个ViewResolver对其解析并获取View对象
  7. 当得到真实对象的Veiw,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染返回视图(jsp、pdf、xml等)给客户端

springmvc

参考资料

  1. Spring MVC 流程图

转载自伯乐在线 - brucefeng

常常听到做业务的程序员抱怨自己现在做的业务没有意思,学不到东西,用不到新技术,用的也都是翻来覆去的技术,得不到成长。很多程序员在经历这个过程时,很多调整不了也就离职了,也许走向了一个新的技术兴奋点,有些可能是换了个新的业务继续循环。那我们程序员在遇到这种事情的时候应该怎么调整,应该向哪个方向走。

现在关于程序员的三观(技术观、产品观和数据观)已经算是普天盖地了,那什么是业务观。

业务开发最好的体验就是从一个业务从起步-> 快速发展->业务稳定发展->…… 的过程,而在业务不同的过程中能够清晰定位开发人员在业务中的角色,能够从技术的角度支持业务。

1. 程序员的三观

1.1 技术观

技术是程序员的核心竞争立,什么才是好的技术观。

好的技术观应该是不排斥新技术,不排斥自己未深入了解的技术。很多新人,甚至很多工作两三年的开发者会陷入一种误区,对一种语言极度热爱,而对其他的一些语言极度鄙视,变成某种语言宗教成员;作为程序员很多时候像是在做学术一样,需要不断探索新的领域,一些技术需要深入掌握,很多技术需要大概知道原理是什么,大概有哪些特性,兼容并包,在一项业务需要的时候能够更好的技术选型。

不同的技术很多时候能够开拓技术眼界,以程序语言为例,在并发实现的问题上:

不同的方式有着自己的优缺点,在实际应用中,我们可以以这些为借鉴解决我们的实际问题,如最近我们就在KTV 预订流程中采用了Channel的模型来抽象并实现业务。

1.2 产品观

技术人员在实现产品需求的时候,首先跳入脑海的是实现产品的技术成本,如实现这个产品会对现有的项目造成多大影响,开发起来有多麻烦等等。考虑这些成本是很有必要的,有了这些成本考虑才能更好的衡量这些需求值不值。但是如果仅仅止步于此,那还没有形成很好的产品观。

作为程序员不仅仅要理解产品的实现细节,我们还要知道产品的动机、定位和防线,知道产品为谁而做、为何而做。

例如在《漫谈工程师的三观》 文章中关于用户登录的产品就是一个很好的例子:

比如说每个在线的系统都有密码重置的功能 —— 我们看看,密码重置的惯例是什么?

  • 用户发送密码重置请求后,系统给请求的邮箱发一个重置邮件
  • 重置邮件里有个会在指定时间内过期的一次性链接,用户点击后进入到密码重置页面
  • 用户设置密码后,可以用新密码登录

然而,这样一个简单的功能,有人会把它做成这样:

  • 用户发送密码重置请求后,系统给请求的邮箱对应的账号设置一个随机密码,并发一个邮件告知随机密码
  • 用户使用这个随机密码登录

1.3 数据观

数据是真实世界在产品上的一个投影(projection)。好的工程师同样也应该是对数据敏感的工程师。Learn startup 教给我们:build – measure – learn 的循环,这与其说是做产品的方法,不如说是我们学习万事万物的方法。

build–measure–learn

所以数据观的第一步是知道测量什么。想要知道测量什么,需要知道某个产品最重要的 KPI 是什么。 例如我们现在在做的KTV预订,最重要的是预订订单数,其次是预订成功率,再细化到预订系统内部就是各预订渠道的预订成功率。

测量只是第一步,接下来是分析和解读数据。分析和解读数据的能力是工程师的数据观的重要组成部分。

数据分析和解读数据之后,需要形成相应的措施,如果业务中存在缺陷或者需要优化的地方,就需要形成产品需求,推动业务和产品的发展,这也许就是人人都是产品经理的一个意义吧。

2. 业务观

业务观是一个更高更广的一种视角,无论是技术、产品还是数据分析都是为了业务更好的发展,如果让业务更好的发展,这就需要更好的业务观。正确的技术观、产品观及数据观是支持业务的基础,但是一个业务不仅仅拥有这三个方面。做一个业务需要知道业务的流程、必要的业务细节。

业务中需要有产品,这些产品大概如何推广,销售环节是如何的,每个环节技术如何提供帮助,以业务的视角来看,现在的产品和技术是否合理,能否提供更好的业务模式。

2.1 与业务人员的沟通

很多开发人员比较讨厌与业务人员(销售,地推人员,运营人员等)沟通,因为总觉得和这些人不再一个频道上。其实很多时候业务人员是挡在真实用户的最后一层,这一层更加理解真实用户的需求,比真实用户能够进行一定的需求总结。倾听业务人员说产品中不通的地方,往往能够找到系统和产品中的缺陷。

2.2 技术的角度看业务

相比业务人员,技术人员有着技术优势,能够从技术角度更好的抽象业务需求。业务人员提出的大多数想法或需求,通常在很短的时间内,便可以基本判定技术实现方案的可行性。