经常我们在设计一个系统的时候,需要在系统启动的时候把一些模块或类加载到内存中或者说Java虚拟机中。但是这些模块都是相互依赖的,那么我们怎么处理呢。也许你会说,这个简单,我们在加载这些模块或类的时候,先加载模块或类中的基本属性,或者说不依赖别的模块或别的类的部分,然后等待加载完这些模块的基本属性后,再加载相互依赖的部分。
其实上边说的这个方法确实可行,但是加载的代码怎么写呢。我们系统的总体设计是这样的,负责加载的程序称为控制层,而被加载的模块统称为模型层,而控制层和模型层之间是不能强耦合的,也就是说至少是面向接口编程的,换句话说,我们在控制层根本就不知道加载的那些模块的具体情况,所以加载的代码不能跟模块的具体实现强耦合在一起,著名的依赖倒转原则(DIP):依赖于抽象,不依赖于具体,说的就是这个意思。
那么我们究竟怎么办呢?
这个并不难办,我们在设计各个模块的时候,每个模块的主类都实现2个方法,baseInit方法,extInit方法,baseInit用来实现加载没有依赖关系的属性,extInit用来加载有依赖关系的属性。在控制层,先分别执行每个模块的baseInit,执行完后,再阅读全文>
发表于 @ 2010年02月08日 22:39:00 | 评论( loading... ) | 举报| 收藏
登录mysql slave服务器,执行show slave status命令,一般显示以下参数的状态;
Slave_IO_State: Waiting for master to send event
Master_Host:192.168.0.1
Master_User:repl_user
Master_Port:3306
Connect_Retry:60
Master_Log_File:mysql-bin.000010
Read_Master_Log_Pos:2562541
Relay_Log_File:mysql-relay-bin.000012
Relay_Log_Pos:1233
Relay_Master_Log_File: mysql-bin.000222
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
Replicate_Do_DB:
主要参数说明下;
Master_Host:主服务器的ip地址
Master_User:主服务器上的一个用户:专门用于从服务器的复制
Master_Port:主服务器的阅读全文>
发表于 @ 2010年02月05日 15:27:00 | 评论( loading... ) | 举报| 收藏
Linux系统:
在startup.sh开始处中增加如下内容:
declare -x CATALINA_OPTS="-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8788"
Windows系统:
在startup.dat文件的中增加如下内容:
SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8788
然后启动Tomcat即可
阅读全文>
发表于 @ 2010年02月03日 23:29:00 | 评论( loading... ) | 举报| 收藏
MySQL replication是一个异步复制的过程,从一个Master instance到多个Slave instance的复制过程主要由三个线程来完成,其中Slave端由2个线程(SQL线程和IO线程),Master有一个IO线程。MySQL replication功能使用的前提是必须打开MySQL的2进制日志功能,也就是binary log. 关于binary log的细节,读者朋友可以参考博客http://blog.csdn.net/chuan122345/archive/2009/12/03/4927970.aspx或相关资料.阅读全文>
发表于 @ 2010年02月02日 22:39:00 | 评论( loading... ) | 举报| 收藏
我们用Master-Slaves架构解决了读压力比较大的应用,而我们用Master-Master架构解决了单点服务问题,提供了系统的可用性。但是有时我们面临巨大的读数据压力,特别是web系统,又需要解决单点服务的问题,为应用提供足够高的可用性。这时我们就需要将这两种架构结合起来。这就是Master-Master-Slaves架构阅读全文>
发表于 @ 2010年02月02日 08:23:00 | 评论( loading... ) | 举报| 收藏
对于MySQL数据库的Master-Slave架构设计,对于一般的对可用性要求不高的系统来说,是一个不错的设计方案,但是如果对可用性要求较高,就会存在一定的问题,我们先看看Master-Slave架构的特点:一个Master作为主数据库服务器,主要功能是负责处理应用客户端的写数据处理,还担当众多Slave数据库复制数据源的角色。多个master主要是负责应用客户端的读数据处理。但是我们的Master数据库服务器难免会出现故障而停机,或者系统需要停机升级,这时就需要短暂的停机,从而导致系统无法处理写数据业务。这对于一些高可用性的系统来说是个无法接受的问题,因为很多领域的应用系统是需要24小时提供服务的。这时我们可以考虑Master-Master架构。阅读全文>
发表于 @ 2010年01月31日 21:31:00 | 评论( loading... ) | 举报| 收藏
为了应用系统的可伸缩性,往往需要对数据库进行scale out设计,scale out设计也就是通过增加数据库处理节点来提高系统整体的处理能力,即增加数据库服务器的数量来分担压力。通过这种方式系统的伸缩性增强了,成本也降低了,但是系统的架构复杂了,维护困难了。难免出现系统的宕机或故障。因此,理论上来说,系统的安全性(可能数据丢失)降低了,可用性也降低了。那么要提高数据安全性,以及系统的高可用性,很简单的办法就是所有软硬件都避免单点隐患,所有数据都保存多份。从技术上来说,就可以通过数据库复制技术实现。MySQL的Replication技术就是数据库复制的实现手段之一阅读全文>
发表于 @ 2010年01月29日 23:38:00 | 评论( loading... ) | 举报| 收藏
在维护一个系统的时候,发现以前的程序员在设计程序的时候,对于实体类的id都设计为对象类型的Long,而不是原始类型的long,据说这样设计是因为对象类型的Long没有值的时候时NULL,因此可以通过其值是否为null来判断所表示的实体类是否已经在在数据库中存在,也就是在添加和更新时做判断使用,因为大多数程序员都习惯用一个save方法,来处理add和update操作,而通过id是否有值来判断是add还是update.就是为了这个小小的功能,而选择Long,我个人不是很喜欢,因为用其作为id,会带来一些缺点,可以说缺点大于优点.阅读全文>
发表于 @ 2010年01月27日 22:15:00 | 评论( loading... ) | 举报| 收藏
平时经常用linux的free命令查看内存信息,今天因为mysql系统突然死掉了,而且无法启动。具体现象是一直显示正在启动的进度状态,但始终无法启动,平时启动几秒就完成了的。所以肯定有问题。于是准备查看下是不是日志信息多了,占满了硬盘空间。突然发现一个问题,怎么查看一个文件和目录的空间占用情况呢,以前都用ls -al 命令,可以显示文件或目录的大小,但是总感觉不太直观,网络搜了下,发现du命令是行使这个职能的专业工具:显示目录或文件的大小。呵呵,很方便,只需要du -sh fileName or directoryName 就可以显示指定的目录或文件的大小。而且这里的文件名或通配符,如果du -sh * 则显示当前目录所有的目录和文件的大小。至于大小的单位,可以使用-h参数自动调整,超过1Kb的显示单位为K,超过1mb的显示单位为m,依此类推,很直观。阅读全文>
发表于 @ 2010年01月25日 12:21:00 | 评论( loading... ) | 举报| 收藏
从横向伸缩和纵向伸缩的优缺点来看,scale up更适合短期处理问题,因为这样成本低,架构简单,技术上要求也简单,风险也小,特别是系统上线要求比较急,项目进度要求比较紧的情况下,scale up还是不错的选择。但是对于一个需要长期运维的系统来说,scale up不能从根本上解决问题(除非业务量和数据量一直不上去,呵呵,这估计是大家都不希望看到的),因为业务量和数据量上去了,迟早会有性能瓶颈出现的,硬件技术的发展是有限的,很多时候都难以赶上业务的发展,如果数据量持续增加,可能隔不了多少时间,又要升级服务器,经常会更换硬件设备。然而scale out在这方面却有优势,服务器成本低,理论上是可无限扩展,当然技术上的复杂度是会不少,当时值得研究,解决起来也问题不大.可扩展性包括应用系统和数据库的可扩展性,本文的观点对两个方向的设计都适合,当然实际具体的设计时,数据库的scalability设计与应用系统的scalability设计还是有区别的。这个涉及更低粒度的设计,需要具体分析。另外,本文所述仅仅代表个人观点,有不对的地方,希望读者朋友一起探讨,共同研究.
阅读全文>
发表于 @ 2010年01月24日 14:07:00 | 评论( loading... ) | 举报| 收藏
首先明确下类加载的定义,类加载实际上就是将java class文件加载到java 虚拟机中,根据JVM规范的定义,一般分为2种类型的类加载,一种是启动类加载器,另外一种是用户自定义类加载器。一启动类加载器。启动类加载器也有以下三种:Bootstrap ClassLoader、AppClassLoader和ExtClassLoader,这三种classloader在java虚拟机启动时会相继创建,首先启动时加载BootstrapClassLoader,然后BootstrapClassLoader加载ExtClassLoader,然后ExtClassLoader加载AppClassLoader,他们之间是由父子关系的,也就是通过父的classloader加载子classloader.下边分别介绍下这三种不同的classloader。BootstrapClassLoader比较特殊,实际上它不是 java.lang.ClassLoader的子类,是C++编写的,java虚拟机启动时第一个执行,它是java虚拟机自带的装载器,用来装载核心类库,也阅读全文>
发表于 @ 2010年01月23日 00:07:00 | 评论( loading... ) | 举报| 收藏
1.由于查询缓存的使用依赖于class缓存,因此class缓存得超时时间设置的必须大于查询缓存的超时时间,也就是timeToLiveSec这个参数的设置。否则可能因为class缓存得失效导致查询缓存在通过id取对象时从缓存中找不到数据只能从数据库取,导致性能地下。
2.有时程序员因为解决某个问题,没有从全局考虑,把对象从缓存中evict了。可能导致一些其他问题。
3.关于查询缓存的失效机制:只要更新过一个表,那么涉及到这个表的任何查询缓存将失效。所以说hibernate的命中率是很低的,需要根据实际业务的读写比率考虑是否用查询缓存。
4.关于查询缓存失效机制的实现:对于每个查询缓存,hibernate记录了其生成时间,而对于每个表,都有一个更新时间,每次进行数据的更新操作时,都会更新这个更新时间。判断查询缓存失效的原则:只要查询缓存的key对应的sql语句中涉及的表中有一个表的更新时间大于这个缓存的生成时间,则该查询缓存失效。
5.使用hibernate二级缓存必须注意的问题:整个系统必须只通过hibernate写数据,也就是hibernate独占写操作。因为如果通过其他方式如阅读全文>
发表于 @ 2010年01月20日 18:26:00 | 评论( loading... ) | 举报| 收藏
Java中异常一般分为3类,下边介绍下,仅仅是个人理解。
第一种是编译期异常,或者叫check Exception。
编译期异常的特点:
1.系统要求必须在程序里做出处理,否则报编译错误,编译无法通过,也就是说系统强制要求处理,对于处理方式,不外乎直接catch处理和抛出到外层,但是最终还是要处理的。
2.用户自定义一个编译期异常的方法,直接继承Exception类 或其超类Throwable。
第二种是运行时异常
运行时异常的特点:
1.在系统运行期间,由JAVA虚拟机抛出,而且运行时异常不要求程序在编译期强制处理,也就是说即使代码中有些地方很明显会抛出运行时异常,也只有系统运行时才会抛出。
2.用户要自定义运行时异常,必须继承自RuntimeException类,JDK类内置了对继承自RuntimeException的异常在编译期不进行检查。如我们常见的空指针异常:NullPointerException,总是在系统运行时被抛出。
前面两类异常都是都可以恢复的异常。通过修改代码,可以避免异常的发生。
第三种是错误异常。
这类异常代表错误,指程序无法恢复的异常情阅读全文>
发表于 @ 2010年01月20日 10:02:00 | 评论( loading... ) | 举报| 收藏
上篇文章只是讲解的责任链模式的基本应用。其实仔细研究了下,还可以在设计上做些变化,使其更加完美。当然具体变化还得跟实际需求联系起来,下边说说一些需要改进的地方以及其方案。第一个需要改进的地方:
在目前的示例代码中,一个链对象要想获得对下一个连对象的引用,采用的是直接创建的方式处理的。如代码:
// 设置安全验证处理器
this.setValidator(new SecurityValidator());
这里总感觉不太优雅,主要是写得太硬,太死,不够灵活。可以通过以下方法解决这个问题:
将SecurityValidator设置成一个成员变量,然后通过spring注入的其示例。这样InputValidator类的代码就变为如下阅读全文>
发表于 @ 2010年01月19日 13:46:00 | 评论( loading... ) | 举报| 收藏
责任链模式,我想很多人都很熟悉,而且我相信大多数朋友都熟悉用来解释责任链模式的击鼓传花游戏。然而,设计模式是开发前辈们对通用的程序设计方法,通过总结归纳抽象而来的。它对我们的程序设计有很好的指导作用,避免了我们在设计上走太多的弯路。但是正是因为其很抽象,可以说是程序设计领域通用的方法学,是设计中的精华中的精华。所以不是所有人都能理解透。不同技术水平的程序员自然对设计模式有不同的认识。
今天主要说说我对责任链模式的理解,希望读者朋友可以参与讨论。
责任链模式是一种对象的行为模式。在责任链模式里,很多对象都由于持有对下一个对象的引用而形成链,链可以是直线,也可以是环状,或树状。而客户端的请求在这个链上传递,直到链上有对象处理了请求。客户端并不知道最终处理请求的链对象是哪个,也不知道总共有多少个对象负责处理该业务。
其实平常我们的应用系统开发中,很多应用了责任链模式的场景,比如信息多重过滤,各种验证检查。下边我就用基本上每个应用系统都有的登陆验证做介绍。阅读全文>
发表于 @ 2010年01月17日 23:36:00 | 评论( loading... ) | 举报| 收藏
Java虚拟机的内部体系结构也许很少有人去关心,因为对于Java程序员来说,一般只需要跟API打交道就可以了。这些体系结构只是Java虚拟机内部的结构而已。但是如果理解了其内部结构,对于我们开发项目,以及排除系统中的相关故障是由帮助的。各部分的主要功能分别是:
1. 类装载子系统:负责Java类型的装载连接以及初始化。Java虚拟机有两种类装载器,启动类装载器和用户自定义类装载器。启动类装载器是JAVA虚拟机实现的一部分,自定义装载器是JAVA程序的一部分。由不同类装载器装载的类将被放在不同的命名空间中。
2. 方法区:方法区主要存储2类信息,一是被装载的类型信息,从class文件流中提取。二是类型中的类(静态)变量。方法区中的信息是所有线程共享的,所以对方法区的数据访问必须设计成为线程安全的。
3. Java堆:存放java运行时创建的所有类实例或数组。一个java虚拟机实例中只存在一个堆空间,所有线程共享,因此设计程序时也要考虑到多线程访问堆数据的同步问题。
4. Java栈:每当启动一个新线程,JAVA虚拟机都会创建一个新的JAVA栈,用于保存线程的运行状态。JAVA栈中阅读全文>
发表于 @ 2010年01月16日 09:04:00 | 评论( loading... ) | 举报| 收藏
1.reverse(str)函数: 返回颠倒字符顺序的字符串str, 该函数对多字节可靠的.
2.substring(str,start,length)函数:返回str字符串中从开始位置start开始长度为length的字符串。注意,第一个字符的位置为1,而不是0.如果用substring(name,0,2),会返回null.
3.substring_index(str,delim,n)函数:返回字符串str中第n次出现delim字符之前的所有字符,如果n为负数,则表示从反方向开始计数。
4.concat(str1,str2,…,strn)函数:将N个字符串相加。如果有任何一个参数为null,则返回null.参数个数不限制。一个数字参数可以变为等价的字符串参数。
5.replace(str,from_str,to_str)函数:返回字符串str,其字符串from_str的所有出现由字符串to_str代替。阅读全文>
发表于 @ 2010年01月13日 23:33:00 | 评论( loading... ) | 举报| 收藏
领域模型描述的是业务中涉及到的业务实体以及相互之间的关系。因此它可以帮助需求分析人员和用户(或用户代表)认识实际业务,从而成为需求分析人员和用户之间交流的重要工具,是他们共同理解的概念,是彼此交流的语言。而数据模型是系统设计,以及实现的一部分,描述的是对用户需求在技术上的实现方法。用户不需要关心系统的数据模型,但是必须关注领域模型,因为领域模型反映的是问题域的相关业务概念以及其关系,领域模型是用户业务描述的高度抽象,来源于业务需求的描述,同时又可以帮助用户和需求分析人员更好的理解业务需求。
阅读全文>
发表于 @ 2010年01月13日 22:33:00 | 评论( loading... ) | 举报| 收藏
最近在做需求分析,期间涉及到用例模型分析设计等工作,结合实际需求工作经验,谈谈自己对用例的特征的理解,我觉得只有对用例的特征理解清楚了,才能再用例建模时能更好的识别用例,比如哪些是用例,哪些不是用例,而只是执行该用例的一个步骤。
一个完整的用例一般都具有以下特征:
第一 用例都是相对独立的。这就是说,它不需要与其他用例交互就可以独自完成参与者的目的。也就是从功能上来说是相对比较独立的。一个用例从本质上说,体现了参与者的的愿望,不能完整表达参与者愿望的不能称为用例。比如说,创建项目这是一个用例,但是在在创建项目的过程中有选择分类这个步骤,那么选择分类就不能称为一个用例,因为如果不创建项目,是不需要选择分类的。选择分类只是创建项目的一个步骤,不创建项目,选择分类对用户来说,没有任何意义。因为选择分类不能单独存在,不具备相对独立性,所以不是一个用例。
阅读全文>
发表于 @ 2010年01月10日 16:17:00 | 评论( loading... ) | 举报| 收藏
在做需求分析时,特别是在设计分析用例模型时,很多人可能碰到过这样的问题,如何准确划分优先级,根据我的经验,一般需求分析人员对用例的优先级划分上没有具体的原则和标准,往往跟着感觉走,要么是客户认为重要的,急着要实现的功能,优先级就高,当然也很重要。对于什么关键用例,什么重要用例,什么是辅助用例或一般用例,都没有具体分得很清楚,因为他们觉得优先的都重要,反正都是要开发的,客户说什么功能最急需要,那么就完成它,其余所有用例都为一般用例。
其实我也很赞成这部分人的观点,主要是结合实际项目,这种情况太普遍了,所以往往只区分重要和非重要来得更方便。不过既然RUP以及软件工程的需求分析阶段都有这么个概念,而且对用例(场景,类)都分为三个等级:关键(首要),重要(其次),辅助(不错)。那么为了准确理解,并在项目中应用,我个人认为理解清晰它,也还是有必要的。而最重要的是掌握其划分原则。最近参加了些需求分析方面的培训,也了解了一些不同人的观点,结合RUP给出的解释,我做了些总结。阅读全文>
发表于 @ 2010年01月09日 23:19:00 | 评论( loading... ) | 举报| 收藏