1. "We wondered why people were so against using regular objects in their systems and concluded that it was because simple objects lacked a fancy name. So we gave them one, and it's caught on very nicely."--Martin Fowler
POJO类的由来原因。“POJO = "Plain Old Java Object",是MartinFowler等发明的一个术语,用来表示普通的Java对象,不是JavaBean, EntityBean 或者 SessionBean。POJO不担当任何特殊的角色,也不实现任何特殊的Java框架的接口如,EJB,JDBC等等。即POJO是一个简单的普通的Java对象,它不包含业务逻辑或持久逻辑等,但不是JavaBean、EntityBean等,不具有任何特殊角色和不继承或不实现任何其它Java框架的类或接口。”
这个POJO一些c++中对应的结构体,一些枚举类也可以归类至此。
JavaBean的三个部分
1) JavaBean可以调用的方法。
2) JavaBean提供的可读写的属性。
3) JavaBean向外部发送的或从外部接收的事件。
“JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性。名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。” wiki
“javaBean的任务就是: “Write once, run anywhere, reuse everywhere”,即“一次性编写,任何地方执行,任何地方重用”。
Session bean:会话构件,是短暂的对象,运行在服务器上,并执行一些应用逻辑处理,它由客户端应用程序建立,其数据需要自己来管理。分为无状态和有状态两种。
Entity bean:实体构件,是持久对象,可以被其他对象调用。在建立时指定一个唯一标示的标识,并允许客户程序,根据实体bean标识来定位beans实例。多个实体可以并发访问实体bean,事务间的协调由容器来完成。
MessageDriven Bean:消息构件,是专门用来处理JMS(Java Message System)消息的规范(EIB2.0)。JMS是一种与厂商无关的API,用来访问消息收发系统,并提供了与厂商无关的访问方法,以此来访问消息收发服务。JMS客户机可以用来发送消息而不必等待回应。
2. rcp框架处理用户的操作事件是同步的,第一个操作完成之前不会进行下一个事件的处理。猜测ui线程应该唯一,且同步处理用户的操作事件。
淘宝有专门讲服务器架构
3.Eclipse项目用称为SWT的的图形库和工具包取代了Java标准中的AWT和Swing。SWT直接调用了操作系统的图形库,从而使得Java应用程序的Look & Feel 与操作系统的习惯完全一致;更为重要的是,对本地方法的直接调用大幅度的提高了基于SWT 的Java应用程序的运行速度。SWT 的缺点主要在于两点:(1) 不是Java语言标准;和(2) 支持的平台太少。
4. GUI程序的一般特点:
1)一般会抽象出各种控件,窗口,按钮,label之类的
2)各种控件中有各自的消息处理方法
3)为了组织方便,控件一般是按照树形式组织,大控件中包含很多小控件
4)MVC模式用用广泛。
M是数据模型,V是界面展现,但是并不是所有的M模型都可以直接给V来数据展示的,例如有很多V是树的展示(不同的树对于数据格式的要求还可能不一样),而M的模型是一对多的父子关系,或者是一条数据包含很多子信息的形式,这就要求C来实现各个不同的M的数据模型到V所要求的数据模型的展示。这样可以隔离开M与V,当M变化时候,适当改变C即可,V不用改变,或者当V改变的时候改变下C也可以,M不用改变。这也是一般设计模式的一个重要目的,隔离变化。
对于GUI程序,学习或者说使用上最多接触的有两个,一个是事件的产生与处理,另外一个就是控件的使用(复杂控件中区分M与V,写C为主要工作)。
http://www.blogjava.net/youxia/archive/2014/03/04/410608.html
5. RCP中对于EditorPart与ViewPart的理解,主要是从业务功能上来区分,一个功能窗口同时有ViewPart与EditorPart,从使用习惯上来说,一般是人们点击ViewPart上的Viewer从而触发EditorPart上的Editor发生变化。可以理解为一般的Editor都是依赖于特定的Viewer的。
6. bug产生原因
1)新功能增加
2)需求的更改与不确定
3)对原有功能的修改
4)其他设备问题等硬件问题和第三方软件引起
5)特殊情况设计时候未考虑
7.在swt中最基本的就是shell和composite了,下面两个简单的定义:
Shell:窗口顶层容器,是所有控件呈现的基础,一个窗口就对应一个Shell对象。界面上的每个控件,经过一级一级向上级追溯,最终都可以找到Shell容器。
Composite:在Shell之上使用的容器。Composite之上可以摆放任意的其他控件。使用Composite的好处主要包括:一是体现了封装;二是Composite可以单独设置布局方式。
另外的定义:
“Shell是一种没有父控件的复合控件(框架或窗口)。此外它还有一个作为父控件的Display,这通常是默认设置。Shell还可以有子Shell。这些子Shell是与父shell相关的独立桌面窗口(父shell关闭,子shell也会关闭)”《eclipse rcp与spring OSGI技术详解与最佳实践》
简单分析下,shell没有父控件,而它可以包含控件,所以,可以简单理解为shell是composite的容器。composite是一般控件的容器。从“复合控件”的角度看,shell与composite看起来很像,但是他们的要解决的“需求”是差别很大的,shell是个“壳”,简单来说就是用来展示界面的,一个无界面的linux也是有着“壳”与“核”的区分(有点像杏核),著名的“壳”有Bourne Again shell (bash)。所以,最最基本的,swt中,看到的都可以说是一个个的shell,只不过在shell上放置了很多composite。没有composite可以,可以一个一个放控件设置布局,但是没有shell就是万万不行的。
8. 对于display对象的理解:“书写swt程序的步骤,这些步骤是:
1)创建一个Display对象
2)创建一个或者多个Shell对象,你可以认为Shell代表了程序的窗口。
3)在Shell内创建各种部件(widget)
4)对各个部件进行初始化(外观,状态等),同时为各种部件的事件创建监听器(listener)
5)调用Shell对象的open()方法以显示窗体
6)各种事件进行监听并处理,直到程序发出退出消息
7)调用Display对象的dispose()方法以结束程序。
Display:与操作系统沟通的桥梁
每个swt程序在最开始都必须创建一个Display对象。Display对象起什么作用呢?它是swt与操作系统沟通的一座桥梁。它负责swt和操作系统之间的通信。它将swt/JFace的各种调用转化为系统的底层调用,控制操作系统为swt分配的资源。同时我们也可以通过Display对象得到操作系统的一些信息。
Display是一个“幕后工作者”,它为swt/JFace提供支持,但是你并不能够从某个用户界面中看到它的影子。
在前面的Hello,world!程序中,我们可以看到构建一个Display对象是和普通的Java对象一样通过构造函数实现的。它为实现图形界面准备了最基本的条件。而在程序结束时我们必须显式地调用dispose() 方法来释放程序运行中所获得的资源。一般来说,一个程序只需要一个Display对象,当然没有人禁止你创建多个Display对象。但是在swt的javadoc中,我们可以看到关于这个问题一些描述:
“Applications which are built with SWT will almost always require only a single display. In particular, some platforms which SWT supports will not allow more than one active display. In other words, some platforms do not support creating a new display if one already exists that has not been sent the dispose() message.”
Display有着众多的方法,我们不可能一一介绍。在这里只挑选几个可能会比较常用的作一些简单介绍。
1)setData()和getData():这一对函数允许我们为Display对象设定一些数据,setData()的参数中key和value类似于我们在使用Map对象中key和value的含义。
2)getShells()得到关联到该Display对象的所有没有dispose的Shell对象
3)getCurrent()得到与用户交互的当前线程
4)readAndDispatch()得到事件并且调用对应的监听器进行处理
5)sleep()等待事件发生
通过Display的方法来查询操作系统:哪个控件获取了焦点,当前打开了哪些窗口等等。简单的说,它的功能在于实现了窗口的管理。Shell需要响应一些事件,其中某些是由操作系统引起的,另外一些是由用户引起的,如用户点击了最大化按钮以及关闭Shell创建的窗口等。事件循环一直侦听这些事件,然后将这些事件转发给相应的处理程序,这是由Display类的readAndDispatch()方法来完成的。这意味着,你创建的每个Shell必须具有它自己的事件循环。如果创建的Shell没有事件循环,或者事件循环失效的话,它马上就会被除去。一般情况下,事件循环会一直执行下去,直到Shell类的isDisposed( )方法返回值为true(即窗口已被用户关闭)为止。
”
Display主要的任务就是适配器的角色,可以适应不同的系统,因为是“跨平台”么,与操作系统直接打交道,例如把各个操作系统不同的事件,转成客户端统一的事件。
参考:
http://blog.csdn.net/chulaixi/article/details/3095478
9. RCP中几个主要类的职责,Activator是管理插件的基本生命周期的,这个Activator会写到配置文件中去。Application管理WorkbenchAdvisor的声明周期,一般在Application的start中创建。WorkbenchAdvisor管理WorkbenchWindowAdvisor的生命周期,在createWorkbenchWindowAdvisor中创建。WorkbenchWindowAdvisor管理ActionBarAdvisor的生命周期,一般在WorkbenchWindowAdvisor的createActionBarAdvisor中创建。
9.java 的观察者类
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to indicate
* that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and the <code>arg</code> argument.
*
* @param arg any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
java 的 Observable 类中的notifyObservers方法,“We don't want the Observer doing callbacks into arbitrary code while holding its own Monitor. The code where we extract each Observable from the Vector and store the state of the Observer needs synchronization, but notifying observers does not (should not).”这句有点像执行线程任务的时候,执行线程从缓冲线程拷贝一份任务,然后执行一样,减少锁持有的时间(synchronized的范围在update之前结束),这也暗示了,这个方法可能在另外一个线程执行,多线程的观察者。
10. 如果库中使用的是旧版编译器(例如2005)编译的,在新版的编译器下(例如2012),库中的有些类是无法使用的例如(string),报找不到符号的错误。string在旧版编译器中编译的结果在新版本里有区别,解决方法是把库拿到vs2012重新编译.
《Exceptional C++》类型安全(type-safe)
11. 在windows下,使用perfmon可以长时间监视性能并生成报表。
(1)查看进程的Process:%Processor Time值
每个进程的%Processor Time反映进程所消耗的处理器时间。用不同进程所消耗的处理器时间进行对比,可以看出具体哪个进程在性能测试过程中消耗了最多的处理器时间,从而可以据此针对应用进行优化。
(2)查看每个进程产生的页面失效
可以用每个进程产生的页面失效(通过process:PAGE FAILURES/SEC计数器获得)和系统页面失效(可以通过memory:PAGE FAILURES/SEC计数器获得)的比值,来判断哪个进程产生了最多的页面失效,这个进程要么是需要大量内存的进程,要么是非常活跃的进程,可以对其进行重点分析。
(3)了解进程的Process:Private Bytes
Process:Private Bytes是指进程所分配的无法与其他进程共享的当前字节数量。该计数器主要用来判断进程在性能测试过程中有无内存泄漏。例如:对于一个IIS之上的WEB应用,我们可以重点监控inetinfo进程的Private Bytes,
如果在性能测试过程中,该进程的Private Bytes计数器值不断增加,或是性能测试停止后一段时间,该进程的Private Bytes仍然持续在高水平,则说明应用存在内存泄漏。
12.
通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。由于外部网络上的主机并不会配置并使用这个代理服务器,普通代理服务器也被设计为在Internet上搜寻多个不确定的服务器,而不是针对Internet上多个客户机的请求访问某一个固定的服务器,因此普通的Web代理服务器不支持外部对内部网络的访问请求。当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务。此时代理服务器对外就表现为一个Web服务器,外部网络就可以简单把它当作一个标准的Web服务器而不需要特定的配置。不同之处在于,这个服务器没有保存任何网页的真实数据,所有的静态网页或者CGI程序,都保存在内部的Web服务器上。因此对反向代理服务器的攻击并不会使得网页信息遭到破坏,这样就增强了Web服务器的安全性。
ps:通常来说的“代理”代理的对象是client,为client提供代理服务,而所说的反向代理,其实是为server提供代理服务。“反”字是说从client到server的反转。
13. Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 服务器。在高连接并发的情况下,Nginx是Apache服务器不错的替代品,能够支持高达 50,000 个并发连接数的响应。
14. http://www.ibm.com/developerworks/cn/java/j-javaauth/ java 授权内幕
15. 协议处理的分层。协议的解析,处理(可以调用通用方法),回复,可以单独封装。在java中可以封装成jar包,利用反射机制加载所有的class,在把这些协议处理类添加到处理对象池中。java的“协议插件”更为灵活,因为有了反射机制,以前代码基本不用修改,只添加一个编译后的class文件即可。而c++中还要在插件初始化的地方订阅协议。
16.自己理解的项目流程,需求收集,需求评审,概要设计,详细设计,编码,测试,bug修改,测试,生成文档,结束。其中详细设计与编码大概会占用四分之三资源。
开发中用到的管理工具有测试用例管理工具、测试bug管理工具(有禅道,bugfree可用)、代码管理工具(svn,github)、文档管理工具。
开发中需求收集与分析是比较重要的一个部分,需求过滤不全(不是越多越好)会多做无用开发,需求分析不全开发后期调整成本很大。
17.分支管理模式 http://www.uml.org.cn/SoftWareProcess/201002094.asp
版本管理也是比较麻烦的一件事,单分支管理在维护阶段会出现较大问题:如果开发周期较短测试1.0版本时正在开发1.1版本,需要修改1.0版本bug;即时开发周期长,但开发1.1版本时1.0版本出现重大问题需要立即修改;或者开发1.2版本时,1.1版本有功能上增加或减少;上述问题修改时候都会对版本的稳定性造成影响。分支管理的目的就是维护代码的稳定性,能够持续的开发、发布、测试。
ps:对于分支管理需要注意的关键点有:开发新功能、测试、bugfix、hotfix(紧急修改)、发布、代码合并(有方向)。
各个管理模式有各自优缺点,而且有各自使用的环境。例如一些定制的功能,就不能再主干上开发,必须在分支上进行,这个时候,先锋主干或者单分支等在主干上开发新功能的就不大适用。
另外不同的管理模式对于代码的设计也有要求,单分支模式上,要求代码有开关配置、功能上有较低的耦合性、框架增删功能灵活。否则会造成代码的混乱,单分支模式一般适用于项目刚启动没有进入维护阶段的时候。
3分支方案的简单开发实施方法见下表:
分支名称 源分支 开发方式 对应版本
主干(Main) 无 测试人员进行测试的专用分支,除非是修复测试人员提出的错误,否则开发人员不能修改该分支 当前正在测试的版本-Beta
开发(Development) 主干(Main) 开发人员主要进行开发的专用分支,其他人员无需使用该分支 当前正在开发的版本-Dev
发布(Release) 主干(Main) 除紧急修复外,开发人员不能进行任何修改;发布人员专用的分支 当前已经发布的版本-Live
http://thinkernel.bokee.com/4518935.html
18. AAA是验证、授权和记账(Authentication、Authorization、Accounting )三个英文单词的简称。
1、 验证(Authentication): 验证用户是否可以获得访问权限。
2、 授权(Authorization) : 授权用户可以使用哪些服务。
3、 记账(Accounting) : 记录用户使用网络资源的情况。
19. 开发中抽象需要视需求而定,像门禁系统,客户端协议到应用服务器,在到接入服务器,在到设备,协议可能通过很多次转换,而当在增加设备的时候,“抽象”的结果是增加了工作量,因为不同设备参数,字段相差太大,抽象只是增加了很多中间很多不通用的环节。在这种情况下,可以适当减少协议流程,客户端到应用服务器后,应用服务器应直接组成设备能够识别或者半识别(可以一个字段携带命令数据)的字节命令,到前端直接发送给设备即可。如果应用服务器在经过一次协议转换,那么接入服务器又要对解析解析转换,多了协议流程,而且不通用。
20. 对实体的管理,可以参考数据库表,例如字段、“继承”关系(扩展表)、父子关系。如果有父子关系那么在设计中对象实体中最好体现出来,这样在维护设备的同步(父设备不在子设备同样删除)等逻辑上会清楚很多。对于实体的管理,可以使用一个“ObjectManager”类似的工具类,把所有的设备id与实体放入map中,方便查找使用。类似于数据库的索引。对于同一类设备,一般也会有一个Manager的管理类,可以用作对同类设备的一些配置,调试命令等。
20. 对实体的管理,可以参考数据库表,例如字段、“继承”关系(扩展表)、父子关系。如果有父子关系那么在设计中对象实体中最好体现出来,这样在维护设备的同步(父设备不在子设备同样删除)等逻辑上会清楚很多。对于实体的管理,可以使用一个“ObjectManager”类似的工具类,把所有的设备id与实体放入map中,方便查找使用。类似于数据库的索引。
21. 对于Session与Bus,bus是对通信的的抽象,可以理解为“通信总线”(通信方式可以为tcp也可以为串口,sdk等),Session为会话管理,是对Bus的更高一层封装,更加面向对象,可以附加一些建立规则,权限验证,保活处理等。
22.
reentrantlock & synchronized
这两个锁都是可重入的。
synchronized是对对象或者类(如果使用的)加锁,锁的释放由函数作用域结束后自动运行。而reentrantlock锁必须是显示的释放(一般在try catch的finally中),利用了“finally一定执行”的特性(类似c++中析构函数一定执行)。
语义上两者差不多,但reentrantlock提供了一些额外的功能。
1)reentrantlock可以设置fairness参数。
reentrantlock在的注释:
* <p>The constructor for this class accepts an optional
* <em>fairness</em> parameter. When set {@code true}, under
* contention, locks favor granting access to the longest-waiting
* thread. Otherwise this lock does not guarantee any particular
* access order. Programs using fair locks accessed by many threads
* may display lower overall throughput (i.e., are slower; often much
* slower) than those using the default setting, but have smaller
* variances in times to obtain locks and guarantee lack of
* starvation. Note however, that fairness of locks does not guarantee
* fairness of thread scheduling. Thus, one of many threads using a
* fair lock may obtain it multiple times in succession while other
* active threads are not progressing and not currently holding the
* lock.
* Also note that the untimed {@link #tryLock() tryLock} method does not
* honor the fairness setting. It will succeed if the lock
* is available even if other threads are waiting.
*
* <p>It is recommended practice to <em>always</em> immediately
* follow a call to {@code lock} with a{@code try} block, most
* typically in a before/after construction such as:
*
* <pre>
* class X {
* private final ReentrantLock lock = new ReentrantLock();
* // ...
*
* public void m() {
* lock.lock(); // block until condition holds
* try {
* // ... method body
* } finally {
* lock.unlock()
* }
* }
* }
* </pre>
默认的“公平”参数是false的,也就是说一般情况下不推荐使用这个参数,会非常影响throughput。
2) reentrantlock 有 tryLock方法:
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException
在获取锁“超时”后就退出锁的竞争。
3)reentrantlock 能与 Condition 一起使用,类似于linux下pthread_condition_wait。
后两种其实是锁应该有的方法,只不过与synchronized比而言。synchronized优势就是从编码上来说,使用方便,不容易出错(自动释放锁)。
http://uule.iteye.com/blog/1488356
http://ifeve.com/understand-condition/