paulwong

#

工期估算那点事

周末听了项目管理的课程,很有感触,有很多记忆深刻的点,比如不要揣摩要提问,要先管理后产品,胜者先胜而后战,败者先战而求胜。然而,让我印象最深的是估算工时这点事,不禁让我想起自己的经历来。
最开始刚参加工作时是在一家翻译公司做它内部的协同系统,两个程序员,老大和我,老大是30岁的老程序员,安排工作很随性,每天早上,点点系统,然后想想接下来要做什么,然后,叫上我,说,把这棵树实现一下吧,然后,再说,需要多长时间?我想一会儿,不就是一棵树吗,说,1小时。老大点点头,说,好,1天。再一天,老大又交给我一项任务,这次任务量大一些,要实现一个完整的模块,我同样是想了想,说3天,老大点点头,说,好,9天。老大总是这样,只要是我作出的估算,他总要乘以3,对此我是不以为然的,这也太保守了。不过好消息是,一年下来我们从未加过班,几乎所有的工作都按计划完成了,日子过得轻松而又悠闲,经常有些时间写点自己喜欢的其他代码,一点也不像程序员。

第二份工作就是IT公司了,做企业应用开发。老大使用干特图来进行工期管理,项目开始之前,老大已经分好大的模块了,这些模块比我第一家公司所谓的模块要大的多,需要以周来估算。这天,老大叫上我,问,这个门户的模块需要几周完成?我想一想,门户以前没有接触过,学习需要一周,开发需要两周,再留一周测试,说,四周。老大点点头,说,好,我再给你加一周学习时间,于是用鼠标在project上拖出一条长长的蓝线来。几个程序员每个都拖出一条蓝线来,三个程序员,八个模块,蓝线短的就再估算一个模块,这样,一条一条蓝线拼起来,最长的那条就成了关键路径,也决定了交付日期,交付日期定在五个月以后。于是就开始开发,那时年轻,无知者无畏,还是单身,加班就不是问题,三个人周六都在公司,吭嗤吭嗤,还真在五个月后给吭嗤完了。于是开始请测试妹妹测试,这一测试问题就来了,很多模块根本就是不可用,只是能够增删改查,很多功能点都没有考虑到,易用性就更别谈了,也难怪,系统设计、实现、测试都被一个只会写代码的程序员包了,既当运动员又当裁判员,能想清楚才怪,于是继续吭嗤,这不吭嗤还好,一吭嗤不得了,又吭嗤出五个月来,再看看jira,几百个bug,每个人都很绝望,老大手一挥,说,哪个软件没有bug,停止开发,修复最重要的bug,然后发布。

第二个项目做完,开始反思,为什么延期这么长估算这么不准,想了很久,觉得是因为估算的粒度太大,时间超过一周,对估算的开发量实际就失去计算了,只剩下一个大概的印象,而为了不成为关键路径不在老大面前丢脸,拍胸脯的情况也发生了,没事,加几个班就搞定了。同时,缺少系统需求说明,这样,在一个错误时间内完成一个不可能完成的任务,质量可想而知,赶进度献礼工程不仅政府在做,程序员同样在做。

这样,到了第三年,自己开始负责一个项目了,吸取了教训,开发估算时,估算的工作量不能超过1周,一旦超过就需要继续分解再进行估算。估算下来,这个项目需要四个月完成,又想起第一个老大的乘三法则,心里颤了一下,难道需要12个月?不能这样,这样这个项目就被取消了。自己带了侥幸的心理,团队的成员都很强,事后也证明这个团队的个人能力都很强,因为有两个人现在在知名外企,一个在淘宝,一个在腾讯,小公司组成这样豪华的阵容是很难得的,唯一不幸的是,我是那个项目经理。我把交付时间定在了四个月之后,开发进度整体还是顺利的,稍微有延期,每周需要延一到两天,这样,我把时间又延长了一个月。天知道,意外发生了,因为我的一句批评,一个成员离职了!我痛哭的发现,项目又要延一个月了,于是,接下来,我就流涕了,六个月时间,公司没有那么多钱投入了!我开始加班,要求其他人也加一些班,意外接着发生,有人生病了,有人有急事要请假了,到最后,终于发现,按估算完成是完全不可能的。最后,项目就被取消了,悲催的项目经理。

继续反思,为什么估算不准,这次我自以为原因很清楚,就是没有考虑项目风险,没有考虑到人会离职,没有考虑到人会请假,没有考虑到人会生病,甚至,没有考虑到人一天工作的产出不是八小时。我太乐观了。我再一次想起来我的第一个老大。

新的公司,新的估算方式,不再一个人估算而是一伙人估算,特性不估算,故事点再估算,没有需求不估算,不一次性估算,迭代估算。这次似乎没有问题了,但客户总是需要一个大的时间点的,于是每个迭代都会排定故事优先级,确保交付前交付的是最有价值的,此外,还有专职的业务分析和漂亮的测试美眉,一切看起来都很好。新公司第一个项目也确实轻松的,但第三个和第四个却都失败了,第三个项目在遇到一个很难解决的性能问题时陷入了一片混乱当中,迭代经理甚至自己都失去对整个项目的可视化了,她不知道项目上线究竟需要满足什么条件,于是项目在一次次的下周二上线的空头承诺中成了整个公司的笑柄。幸福的项目总是相似,不幸的项目各有各的不幸。第四个项目在一次项目中期的架构重写中崩溃了,重写耗去了团队太多的时间,而由于对未知领域知识的不正确估算再次令项目雪上加霜,而更加致命的是,项目目标直到最后一刻也没有发生变化,依旧是要在六个月后上线,于是,程序员们就内存溢出了。

乐观、管理混乱、领域知识不熟,这些都导致了项目延期,工时等于工期吗?不等于,工期永远是假的,工时估计的准确,混乱的管理同样会毁掉它。更严重的不是项目延期,而是项目本来就是老板拍脑袋的结果,想想某个项目,如果不说我们能快速交付就根本得不到它,而得到它后怎么办,那只能拜春哥了!

posted @ 2011-12-12 01:10 paulwong 阅读(388) | 评论 (1)编辑 收藏

配置负载均衡 配置集群

     摘要: 所需软件   Apache :apache_2.0.63 1 个 【apache_2.0.63-win32-x86-no_ssl.msi】   Tomcat: apache-tomcat-5.5.23 (zip版) 2个   mod_jk:: mod_jk-apache-2.0.55.so 1个   部署说明   在同一台机器上部署,即充当Apache负载服务器,又安装两个Tomcat Web服务...  阅读全文

posted @ 2011-12-09 00:45 paulwong 阅读(293) | 评论 (0)编辑 收藏

application server 下的任务异步/并行执行方案

在application server下,比如常见的weblogic,glassfish,jboss等,由于javaee规范的要求,一般不容许直接启动线程。因此在常见的异步/并行任务执行上,会遭遇到比普通javase程序更多的麻烦。

典型例子,在javase中,jdk1.5后就引入了java.util.concurrent包,提供Executor这个非常好用的框架,完美的满足一下典型需求:

1. 同步变异步
请求进来后,将请求封装为task,交给Executor执行,原线程可以立即返回
2. 并行执行
请求进来后,将请求拆分为若干个task,例如下发短信,有100个收件人就可以按照每个收件人一个task来执行,这样可以通过Executor来并行执行这些请求,远比循环执行要快的多。

3. 等待任务结束
有时有要求调用线程必须等待所有任务完成后再继续运行的需要,此外还有超时等细节设置要求。

而在application server,为了避开自己启动线程的弊端,只好通过其他的方式来完成类似的功能。

目前我们的项目开发中主要有三种实现方式:

1. jms queue

通过jms来实现异步和并发,然后自己通过编码方式完成调用线程等待所有任务执行成功。

这个方案比较通用,因为jms是javaee的标准,所有的application server上都支持。因此天然具有跨application server的能力。

缺点就比较多了,首先jms是需要实现串行化的,因此对task是有要求,不能串行化的类是不能传递的。另外串行化的性能损失比较大,造成性能和稳定性问题,这个在大压力下比较突出,基本我们目前在考虑放弃这个方案,而且逐步将原有的实现替换掉。
这个方案还有另外一个缺点,配置麻烦,维护困难:需要创建jsm queque, connection factory, MDB等,如果系统中使用的多了,配置起来很罗嗦,修改时容许出错。

2. commonj work manager

这个是weblogic和WebSphere上支持的一个很实用的解决方案,个人感觉使用上非常舒服,配置简单,只要在weblogic-ejb-jar.xml中间中简单配置:

    < work-manager > 
         
< name > wm/taskDistributionWorkManager </ name > 
         
< min-threads-constraint > 
             
< name > minthreads </ name > 
             
< count > 1 </ count > 
         
</ min-threads-constraint > 
         
< max-threads-constraint > 
             
< name > maxthreads </ name > 
             
< count > 100 </ count > 
         
</ max-threads-constraint > 
     
</ work-manager > 


使用时用jdni lookup到就可以使用了。功能和使用方式和executor框架很类似,同样提供future,而且提供一个非常实用的waitAll()方法论支持等待任务完成。

这个方案的性能非常好,和jms相比提升极大,运行也稳定。缺点就是不是标准,只有weblogic和WebSphere执行,在glassfish,jboss上无法使用。

3. JCA work manager

这个是JCA标准了,glassfish,jboss都支持的,和commonj work manager很像,但是,很遗憾的是没有future的支持,而且也没有类似的waitAll()方法,只能自己编码实现。
spring为glassfish提供了一个工具类"org.springframework.jca.work.WorkManagerTaskExecutor",简化了JCA work manager的使用。

JCA work manager的性能和稳定性都还不错,对比jms要好的多。


JBOSS下的配置

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>   
<jboss-web>   
<resource-ref id="ResourceRef_1163654014164">   
      
<description>WorkManager</description>   
      
<res-ref-name>jboss.jca:service=WorkManager</res-ref-name>   
      
<res-type>org.jboss.resource.work.JBossWorkManager</res-type>   
      
<res-auth>Container</res-auth>   
      
<res-sharing-scope>Shareable</res-sharing-scope>   
      
<jndi-name>WorkManager</jndi-name>   
  
</resource-ref>      
  
  
</jboss-web>   


applicationContext.xml


<bean id="taskExecutor" class="org.springframework.jca.work.jboss.JBossWorkManagerTaskExecutor">     
        
<property name="workManagerName" value="WorkManager"/>   
        
<property name="resourceRef" value="true"/>   
    
</bean>   



从目前我们项目的使用经验上看,jms是准备要被淘汰的了(其实我是一直对jms不感冒的,尤其是在有性能要求的地方,想不出用jms的理由)。目前项目要求同时支持weblogic和glassfish,因此commonj work manager和JCA work manager刚好对应于weblogic和glassfish平台。实际使用中,是在这两个work manager上封装了一个通用的接口,然后再有commonj work manager和JCA work manager两个实现,在运行时通过判断平台来自动选择注入其中的一个。

posted @ 2011-12-08 18:58 paulwong 阅读(360) | 评论 (0)编辑 收藏

FutureTask and ThreadPoolExecutor

     摘要: 用ThreadPoolExecutor的时候,又想知道被执行的任务的执行情况,这时就可以用FutureTask。ThreadPoolTask Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.paul.threadP...  阅读全文

posted @ 2011-12-07 15:48 paulwong 阅读(2674) | 评论 (1)编辑 收藏

软件知识大学

如果你对UML感兴趣,建议你按以下顺序学习:
1.UML入门课程:
http://www.umlonline.org/school/forum-25-1.html
2.在线课程:活用UML-需求分析高手:(需金币)
http://www.umlonline.org/school/forum-26-1.html
3.UML视频课程
http://www.umlonline.org/school/forumdisplay.php?fid=128&filter=type&typeid=12
4.在线课程:活用UML-软件设计高手(需金币)
http://www.umlonline.org/school/forum-27-1.html

如果你对设计模式感兴趣:
1.设计模式学院:
http://www.umlonline.org/school/index.php?gid=5

如果你对需求分析感兴趣,建议你学习:
1.视频课程:需求分析挑战之旅
http://www.umlonline.org/school/thread-361-1-1.html
2.在线课程:需求分析挑战之旅-疯狂的订餐系统
http://www.umlonline.org/school/forum-111-1.html
3.在线课程:活用UML-需求分析高手(需金币)
http://www.umlonline.org/school/forum-26-1.html
4.视频课程:活用类图,拥抱需求
http://www.umlonline.org/school/thread-466-1-1.html
5.在线课程:需求能力提升训练营(需金币)
http://www.umlonline.org/school/forum-159-1.html

如果你对软件设计感兴趣,建议你学习:
1.视频课程:做一回软件架构师
http://www.umlonline.org/school/thread-589-1-1.html
2.设计模式学院:
http://www.umlonline.org/school/index.php?gid=5
3.在线课程:活用UML-软件设计高手(需金币)
http://www.umlonline.org/school/forum-27-1.html


如果你对软件项目管理(敏捷开发)感兴趣,建议你学习:
1.在线课程:项目管理入门
http://www.umlonline.org/school/forum-115-1.html
2.一系列项目管理相关视频课程
http://www.umlonline.org/school/forumdisplay.php?fid=128&filter=type&typeid=10
3.视频课程:项目管理极速提升(需金币)
http://www.umlonline.org/school/thread-669-1-1.html
4.在线课程:超越敏捷——超级项目管理
http://www.umlonline.org/school/forum-117-1.html

如果你对CMMI(过程改进)感兴趣,建议你学习:
1.视频课程:畅游CMMI
http://www.umlonline.org/school/thread-468-1-1.html
2.扫盲文章:CMMI基础知识扫盲
http://www.umlonline.org/school/thread-73-1-1.html
3.在线课程:Intro to CMMI 中国版
http://www.umlonline.org/school/forum-91-1.html
4.在线课程:CMMI快乐之旅(内容未完整)
http://www.umlonline.org/school/forum-92-1.html

posted @ 2011-12-05 11:23 paulwong 阅读(278) | 评论 (0)编辑 收藏

UML中几种类间关系:继承、实现、依赖、关联、聚合、组合的联系与区别

这是一堂关于UML基础知识的补习课;现在我们做项目时间都太紧了,基本上都没有做过真正的class级别的详细设计,更别提使用UML来实现规范建模了;本篇主要就以前自己一直感觉很迷糊的几种class之间的关系进行整理,让我们在真正用UML进行比如类图设计时能够更加清晰明了;以下就分别介绍这几种关系:

继承

指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性;

实现

指的是一个class类实现interface接口(可以是多个)的功能;实现是类与接口之间最常见的关系;在Java中此类关系通过关键字implements明确标识,在设计时一般没有争议性;

依赖

可以简单的理解,就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、、临时性的、非常弱的,但是B类的变化会影响到A;比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖;表现在代码层面,为类B作为参数被类A在某个method方法中使用;

关联

他体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友;这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的、关联可以是单向、双向的;表现在代码层面,为被关联类B以类属性的形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量;

聚合

聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;

组合

组合也是关联关系的一种特例,他体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合;他同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束;比如你和你的大脑;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;

对于继承、实现这两种关系没多少疑问,他们体现的是一种类与类、或者类与接口间的纵向关系;其他的四者关系则体现的是类与类、或者类与接口间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准备定位是很难的,前面也提到,这几种关系都是语义级别的,所以从代码层面并不能完全区分各种关系;但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖;

posted @ 2011-12-02 02:13 paulwong 阅读(385) | 评论 (0)编辑 收藏

JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用简介

大多数并发应用程序是以执行任务(task)为基本单位进行管理的。通常情况下,我们会为每个任务单独创建一个线程来执行。这样会带来两个问题:一,大量的线程(>100)会消耗系统资源,使线程调度的开销变大,引起性能下降;二,对于生命周期短暂的任务,频繁地创建和消亡线程并不是明智的选择。因为创建和消亡线程的开销可能会大于使用多线程带来的性能好处。

一个比较简单的线程池至少应包含线程池管理器、工作线程、任务队列、任务接口等部分。其中线程池管理器(ThreadPool Manager)的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;任务队列的作用是提供一种缓冲机制,将没有处理的任务放在任务队列中;任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行。下面的代码实现了创建一个线程池,以及从线程池中取出线程的操作。

在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。

1.核心线程(任务):我们定义的线程,即实现了Runnable接口的类,是我们将要放到线程池中执行的类,如实例代码中的CountService类

2.工作线程:由线程池中创建的线程,是用来获得核心线程并执行核心线程的线程(比较拗口哦,具体看代码就知道是什么东东了)。

简单理解就三个概念:线程、线程池和任务。

任务:就是要执行的业务逻辑;
线程:任务是要放到线程中去执行的;
线程池:主要是控制当前正在执行的线程的数量和将要被执行的线程队列。

一、简介
线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)


corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略

一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

当一个任务通过execute(Runnable)方法欲添加到线程池时:

如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。

也就是:处理任务的优先级为:
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue

handler有四个选择:

ThreadPoolExecutor.AbortPolicy()
抛出java.util.concurrent.RejectedExecutionException异常

ThreadPoolExecutor.CallerRunsPolicy()
重试添加当前的任务,他会自动重复调用execute()方法

ThreadPoolExecutor.DiscardOldestPolicy()
抛弃旧的任务

ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务

二、一般用法举例


package com.paul.threadPool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {

private static int produceTaskSleepTime = 10;

private static int produceTaskMaxNumber = 10;

public static void main(String[] args) {

// 构造一个线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3),
new ThreadPoolExecutor.CallerRunsPolicy());

for (int i = 1; i <= produceTaskMaxNumber; i++) {
try {
String task
= "task@ " + i;
System.out.println(
"创建任务并提交到线程池中:" + task);
threadPool.execute(
new ThreadPoolTask(task));

Thread.sleep(produceTaskSleepTime);
}
catch (Exception e) {
e.printStackTrace();
}

}

}

}


package com.paul.threadPool;

import java.io.Serializable;

public class ThreadPoolTask implements Runnable, Serializable {

private static final long serialVersionUID = 0;

// 保存任务所需要的数据
private Object threadPoolTaskData;

private static int consumeTaskSleepTime = 2000;

ThreadPoolTask(Object tasks)
{
this.threadPoolTaskData = tasks;
}


public synchronized void run() {
// 处理一个任务,这里的处理方式太简单了,仅仅是一个打印语句
System.out.println("开始执行任务:" + threadPoolTaskData);
try {
// //便于观察,等待一段时间
Thread.sleep(consumeTaskSleepTime);
}
catch (Exception e) {
e.printStackTrace();
}

threadPoolTaskData
= null;
}


public Object getTask() {
return this.threadPoolTaskData;
}


}


说明:
1、在这段程序中,一个任务就是一个Runnable类型的对象,也就是一个ThreadPoolTask类型的对象。
2、一般来说任务除了处理方式外,还需要处理的数据,处理的数据通过构造方法传给任务。
3、在这段程序中,main()方法相当于一个残忍的领导,他派发出许多任务,丢给一个叫 threadPool的任劳任怨的小组来做。
这个小组里面队员至少有两个,如果他们两个忙不过来,任务就被放到任务列表里面。
如果积压的任务过多,多到任务列表都装不下(超过3个)的时候,就雇佣新的队员来帮忙。但是基于成本的考虑,不能雇佣太多的队员,至多只能雇佣 4个。
如果四个队员都在忙时,再有新的任务,这个小组就处理不了了,任务就会被通过一种策略来处理,我们的处理方式是不停的派发,直到接受这个任务为止(更残忍!呵呵)。
因为队员工作是需要成本的,如果工作很闲,闲到 3SECONDS都没有新的任务了,那么有的队员就会被解雇了,但是,为了小组的正常运转,即使工作再闲,小组的队员也不能少于两个。
4、通过调整 produceTaskSleepTime和 consumeTaskSleepTime的大小来实现对派发任务和处理任务的速度的控制,改变这两个值就可以观察不同速率下程序的工作情况。
5、通过调整4中所指的数据,再加上调整任务丢弃策略,换上其他三种策略,就可以看出不同策略下的不同处理方式。
6、对于其他的使用方法,参看jdk的帮助,很容易理解和使用。

posted @ 2011-12-02 01:07 paulwong 阅读(453) | 评论 (0)编辑 收藏

一个使用GUZZ+SPRING的MAVEN项目POM文件

     摘要: 有依赖的包管理,可以部署到TOMCAT 6.X,可以使用JETTY作开发测试,可以生成站点,作CHECK STYLE,PMD代码检查,代码覆盖率,生成JAVA DOC。 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><project ...  阅读全文

posted @ 2011-11-30 16:18 paulwong 阅读(1475) | 评论 (2)编辑 收藏

在Eclipse中调试Maven项目

使用maven的一个方便之处是可以使用Jetty Plugin来运行web项目。只要maven jetty:run就可以把web项目跑起来了。只是很多时候我们都需要在IDE中进行调试。那如何在Eclipse中调试使用jetty Plugin的web项目呢?
下面我们就来配置一下。
  1. 首先在Run->Externel Tools->Open Externel Tools Dialog.. 打开配置对话框,选中左边的Program节点,右键选择New然后再右边的配置里面输入Name信息,在Main tab下的Location选择你maven可执行文件的全路径(eg:/home/rory/apps/apache-maven-2.0.8/bin/mvn),Working Directory选择你的maven项目(eg:${workspace_loc:/guice-example}),Arguments里输入jetty:run。然后再切换到Environment tab。New 一下变量,name是
     
    MAVEN_OPTS

    value是
    -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8080,server=y,suspend=y

    ok,这一步设置完毕,Apply一下,close关闭

  2. 接下来添加一个Debug,打开Run->Open Debug Dialog..打开Debug Dialog窗口,选中左边的Remote Java Application,右键New输入name,Project里选中要Debug的项目Connection Properties里的Host里设置成localhost,Port设置成上面配置的8080(这里要填JETTY默认启动的端口)然后Apply一下就ok了。

  3. 接下来就可以开始调试了。首先启动第一步配置的Externel Tools配置,然后再运行第二步配置的Debug.就可以看到控制台有mvn jetty:run的输出了。接下来就开如Debug你的项目吧。:)

posted @ 2011-11-30 16:02 paulwong 阅读(4576) | 评论 (2)编辑 收藏

实践:搭建基于maven的Java EE协同开发环境

http://dearshor.iteye.com/blog/272274

posted @ 2011-11-30 00:15 paulwong 阅读(373) | 评论 (0)编辑 收藏

仅列出标题
共110页: First 上一页 88 89 90 91 92 93 94 95 96 下一页 Last