第8 页 共15页« 首页...«678910»...末页 »

最近使用jboss的时候常常出现1098端口被占,不能正常起动的错误:

10:28:57,000 WARN  [ServiceController] Problem starting service jboss:service=Naming
java.rmi.server.ExportException: Port already in use: 1098; nested exception is:
java.net.BindException: Address already in use: JVM_Bind
at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:310)
at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:218)

也不知道是哪个程序占用了这个端口。可以通过修改jboss的配置文件,让jboss使用另外一个端口,来修正这个问题。方法如下:

1,打开jboss的jboos-service.xml文件,在我机上位于D:\prog\jboss-4.2.2.GA\server\default\conf 目录。

2,搜索1098,找到 <attribute name=”RmiPort”>1098</attribute>,修改这个端口号为一个一般不会被用到的端口号,比如12345。

再重启jboss应该就OK了。

Share/Save/Bookmark

February 21st, 2008AOP简介,理解AOP

AOP简介

一. AOP字面意思

AOP = Aspect Oriented Programming 中文意为: 面向切面编程

要掌握AOP就得从aspect,即切面,入手,理解什么是切面,为什么要切面,如何使用切面。

二. 没有AOP的日子

OOP = Object Oriented Programming 面向对象的编程。

兴起于上个世纪九十年代的面向对象编程理念,仍旧是现在编程思想的主流。面向对象的核心思想是抽像问题域的模型成对象,用程序去模拟对象以解决问题。但是在软件系统中还存在着一些问题,它们不易于,或者不适合于用面向对象地方式来解决,比如事务,安全,日志等。看下面:

public class Tool1 {
	public void doSomething() {
		System.out.println("I am doing...");
	}
}
 
public class Tool2 {
	public void doSomething () {
		System.out.println("I am do some other things...");
	}
}
 
public class Main() {
	public static void main(String[] args) {
		Tool1 t1 = new Tool1();
		Tool2 t2 = new Tool2();
 
		t1.doSomething();
		t2. doSomething ();
	}
}

例1

这个程序很简单,容易看得懂。现在新的要求来了,要求在执行Tool1和Tool2的两个方法前后说一句话。如果用过程式的编程方法,我们只要改一下main方法,让它变成这样,看例2:

public class Main() {
	public static void main(String[] args) {
		Tool1 t1 = new Tool1();
		Tool2 t2 = new Tool2();
 
		System.out.println("Going to do something...");
		t1.doSomething();
		System.out.println("Did something...");
 
		System.out.println("Going to do something...");
		t2. doSomething ();
		System.out.println("Did something...");
	}
}

例2

很好,实现目标了,但这存在以下问题:

  • 如果还有其它不是main的调用者使用Tool1和Tool2,我们需要改动所有调用者代码
  • 完成同样的事情却将代码散落在多个地方,复制粘贴不是一个编程好习惯

下面我们来解决这两个问题。为了解决第一个问题,我们可以把代码改动由调用者转移到被调用者里,如:

public class Tool1 {
	public void doSomething() {
		System.out.println("Going to do something...");
		System.out.println("I am doing...");
		System.out.println("Did something...");
	}
}
 
public class Tool2 {
	public void doSomething () {
		System.out.println("Going to do something...");
		System.out.println("I am do some other things...");
		System.out.println("Did something...");
	}
}
 
public class Main() {
	public static void main(String[] args) {
		Tool1 t1 = new Tool1();
		Tool2 t2 = new Tool2();
 
		t1.doSomething();
		t2. doSomething ();
	}
}

例3

好,这样就不需要改变第个调用者的代码了。但是为了实现同样的功能,还是用了太多的代码,好,我们利用伟大的面向对向的能力吧!

public abstract class abstractTool {
	public void doSomething() {
		System.out.println("Going to do something...");
		doSomethingReally();
		System.out.println("Did something...");
	}
 
	protected abstract void doSomethingReally();
}
public class Tool1 extends abstractTool {
	public void doSomethingReally() {
		System.out.println("I am doing...");
	}
}
 
public class Tool2 extends abstractTool {
	public void doSomethingReally() {
		System.out.println("I am do some other things...");
	}
}
 
public class Main() {
	public static void main(String[] args) {
		Tool1 t1 = new Tool1();
		Tool2 t2 = new Tool2();
 
		t1.doSomething();
		t2.doSomething ();
	}
}

例4

好了,这样实现新功能的代码被集在了一个抽象类的方法里了,没有在散落开来,易于维护了。这样的方案是不是就是完美的了呢?不,还不够,它存在着一个严重问题,

  • 必须得修改被调用者的代码
  • 强迫被调用者继承于某个类,这样它将不能再继承其它类

这样做显然很不灵活,假如还有Tool3 Tool4 Tooln…,它们有一些需要这样的功能,有一些不需要,甚至于有时有一些需要,有时有一些不需要,怎么办?我们只好每次变动时都做这样的修改,那太痛苦了。好吧,还有更好的方案吗?也许一开始设计得就有些问题吧?嗯,是的,我们采用工厂模式吧,面向接口编程吧!于是就有了下面的代码:

public interface Tool {
	public void doSomeThing();
}
 
public class Tool1 implements Tool {
	public void doSomethingReally() {
		System.out.println("I am doing...");
	}
}
 
public class Tool2 implements Tool {
	public void doSomethingReally() {
		System.out.println("I am do some other things...");
	}
}
 
public class ToolProxy implements Tool{
	private Tool tool;
 
	public ToolProxy(tool) {
		this.tool =tool;
	}
 
	public void doSomething() {
		System.out.println("Going to do something...");
		this.tool.doSomething();
		System.out.println("Did something...");
	}
}
 
public class ToolFactory {
	public static Tool getTool(String type) {
 
		if("Tool1".equals(type)) {
			return new ToolProxy(new Tool1());
		} else if("Tool2".equals(type)) {
			return new ToolProxy(new Tool2());
		}
		return null;
	}
}
 
public class Main() {
	public static void main(String[] args) {
		Tool t1 = ToolFactory.getTool("Tool1");
		Tool t2 = ToolFactory.getTool("Tool2");
 
		t1.doSomething();
		t2.doSomething ();
	}
}

例5

接口使被调用者不再需要继承于某个类,也使得调用者和被调用者之间解耦。工厂负责组装类,我们可以在工厂里实现通过xml来配置等功能。ToolProxy代理类把新功能性代码集中在一起,便于管理。可惜这个方案还是有些问题的,假如我们不能改动被调用代码,不能强制人家实现某个接口呢?好吧,我们再使用一点花招吧,看下面代码:

public interface Tool {
	public void doSomeThing();
}
public class Tool1Wrapper implements Tool {
	public Tool1 tool1;
	public Tool1Wrapper() {
		tool1 = new Tool1();
	}
 
	public void doSomething() {
		tool1.doSomething();
	}
}
 
public class Tool2Wrapper implements Tool {
	public Tool2 tool2;
	public Tool2Wrapper() {
		tool2 = new Tool2();
	}
 
	public void doSomething() {
		tool2.doSomething();
	}
}
 
public class Tool1{
	public void doSomething() {
		System.out.println("I am doing...");
	}
}
 
public class Tool2{
	public void doSomething() {
		System.out.println("I am do some other things...");
	}
}
 
public class ToolProxy implements Tool{
	private Tool tool;
 
	public ToolProxy(tool) {
		this.tool =tool;
	}
 
	public void doSomething() {
		System.out.println("Going to do something...");
		this.tool.doSomething();
		System.out.println("Did something...");
	}
}
 
public class ToolFactory {
	public static Tool getTool(String type) {
 
		if("Tool1".equals(type)) {
			return new ToolProxy(new Tool1Wrapper());
		} else if("Tool2".equals(type)) {
			return new ToolProxy(new Tool2Wrapper());
		}
		return null;
	}
}
 
public class Main() {
	public static void main(String[] args) {
		Tool t1 = ToolFactory.getTool("Tool1");
		Tool t2 = ToolFactory.getTool("Tool2");
 
		t1.doSomething();
		t2.doSomething ();
	}
}

例6

当你看完这段代码后,如果你想要抓狂,那就抓吧,我能够理解。为了实现这点新功能,我们做了如此大的努力!是不是这样就结束了呢?这就是最终的完美方案了吗?显然还不够:

  • 代码太长
  • 如果有多个类,就需要写多个Wrapper类
  • 如果有多个接口,就需要写多个Proxy类

如果这样的代码就能够让你满意,看来你不是足够懒惰的程序员,你很勤快,愿意为实现这样的功能敲打出一堆代码。但是伟大的懒惰程序员们并不没有停下来。

三. AOP是对OOP的补充

当写完上面的代码后,我们该静下来想一想,我们到底想要对程序做什么,为什么会这样麻烦呢?

我们想要什么?我们想要就是能在程序的调用者和被调用者之间切开一个面,加入新的功能!上面的例子,我们就是想在调用Tool1和Tool2的doSomething()方法时,将调用过程切开一个面,分别在进入和出来时放入两句代码而已。而现在的程序语言恰恰缺少这样把调用过程切开的能力,所以我们需要新的语言,新的能力!这个编程的思想就是AOP,这种能力就是AOP的能力,能够这样做的语言就是AOP的语言。

AOP是对OOP的一个补充,正是OOP缺少了这样的能力,而人们又有这样的需要,所以才会有AOP。AOP并不能代替OOP,正如OOP不能代替过程式编程一样。

四. 理解AOP的语义

AOP中最关键的就是aspect,即切面。切面是以前的语言没有定义的新的概念。要理解切面,就要理解切面几个要素:

1. 切谁 即,对谁的调用会被切开,我们想要加入的新的功能正是针对于这个被切的对象的。

2. 切什么地方 被调用者会可能有多个被外部访问的出入口,为了实现我们的功能,需要被切的那个出入口。

3. 添加什么样的功能 将程序切开,目的是在被切开的地方加入新的功能。

理想状况下,所有的对象都能被切,不管这个对象是什么类型的,是不是final的,是不是nested的等;对象的所有地方都能切,不管是在构建时,调用方法时,调用属性时,调用前,调用后等;任意功能都能添加,切开之后,做什么都可以。

AOP有各种不同的实现,不同实现的能力之间的区别就可以通过上面的三条来衡量。功能最强的AspectJ,可以对任意对象的创建,方法调用,属性调用时做切面,加入任意功能。但是一般情况下我们不需要那么强的能力,能够实现对象的方法调用的切入,就已经够用了,spring里大量使用了这样的能力。

为了使用的方便,一般对方法的切入,分为以下几种:

1. Before 在方法调用前执行,不能控制返回值

2. After 在方法调用后执行,可以控制返回值

3. Throw 在方法异常退出时执行

4. Around 兼有以上三种的能力

五. AOP 实现原理举例

实现AOP有很多种不同方法,大体上可以分为三类:

1. 修改由源程序生的class文件,加入新功能

这一类的代表是AspectJ项目。它在java语言的基础上添加的新的语言和语法。AspectJ有自己的编译器,它会在调用java的编译器生成class文件后,修改class文件。这种方法实现的AOP是最高效的,因为功能的添加是在编译器就加入了,也是功能最强的,所有的地方都可以切入,缺点是需要学习新的语法和需要额外的编译步骤。

2. 动态生成类的子类,通过方法覆盖来添加新的功能

Spring使用cglib在运行时生成类的子类来实现一部分AOP。比如对于上面例子中的Tool1类,spring可以在运行时动态生成一个新的类,类似于:

public class Tool1$4535354 extends Tool1{
	public void doSomething {
		System.out.println("Going to do something...");
		super.doSomething();
		System.out.println("Did something...");
	}
}

例7

这种方法需要被调用对象的类是可以被继承的,方法是可以被覆盖的,还好这一条基本上都能满足,因为大部情况下我们面对的都是普通的java bean。

3. 借助于接口和动态代理类,添加新功能。

Spring在处理带有接口的类的时候采用这种方式。JDK里有一个类java.lang.reflect.Proxy 可以动态地生
成一个实现了某个接口的代理类。例如,spring实现了一个类似于下面的类:
public class ProxyFactory {
	public static Object getProxy(Class[] interfaces,
		Object target) {
		Object proxy = Proxy.newProxyInstance(
			target.getClass().getClassLoader(),
			interfaces,
			new MyInvocationHandler(target);
		);
		return proxy;
	}
 
	static class MyInvocationHandler {
		private Object target;
 
		public MyInvocationHandler(Object target) {
			this.target = target;
		}
 
		public Object invoke(
			Object proxy, Method method, Object[] args)
				throws Throwable {
			System.out.println("Going to do something...");
			Object o = method.invoke(target, args);
			System.out.println("Did something...");
 
			return o;
		}
	}
}

进一步的,我们还可以修改MyInvocationHanlder使其动态化,在invoke方法里执行抽像化的before after
around throw 等建议,这里就写了。有了这个动态代理类,我们就可以不用实现很多的Proxy类了。

六. AOP的标准

为了能够统一对AOP使用的术语和API,国际上出现了AOP相关的组织,比如项目aopalliance等。Spring在使用的aop时就采用这个项目制定的api。关于标准的内容,可以自行去查看相关资料。

七. 在spring中使用AOP

Spring里大量使用AOP,为了能更简单地表达AOP,可以通过xml或annotation对AOP进行描述。详细请看spring的手册。

<tx:advice id="daoTxAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="find*" read-only="true" propagation="REQUIRED">
		<tx:method name="check*" read-only="true" propagation="REQUIRED">
		<tx:method name="*" propagation="REQUIRED">
	</tx:method>
</tx:method>
 
<aop:config>
	<aop:pointcut id="daoOperation" expression="execution(public * com.**.dao.*Dao.*(..))"></aop:pointcut>
	<aop:advisor advice-ref="daoTxAdvice" pointcut-ref="daoOperation"></aop:advisor>
 
	<aop:aspect ref="permissionCheckBean" order="0">
		<aop:pointcut id="permissionCheckPointCut">
</aop:pointcut>expression="execution(public String com.**.action.*Action.execute*()) " /&gt;
<aop:around method="checkPermission" arg-names="pjp " pointcut-ref="permissionCheckPointCut"></aop:around>
	</aop:aspect>
</aop:config>
</tx:method></tx:attributes></tx:advice>

例9

上面的配置中<aop:pointcut>标签定义了一个bean,它能够说明切什么对象的什么地方。比如,expression=”execution(public String com.**.action.*Action.execute*()) and @annotation(requirePermission) 说明在对方公开的反回值为String的,包名符使表达式com.liba.**.action的,类名符合*Action的,方法名以execute开头的,无参数的,这样的方法进行切入。然后<aop:around>标签则表达了,对于上面那样的方法以around方式切入,切入后,在切开的地方执行permissionCheckBean的 checkPermission方法。

Share/Save/Bookmark

上文买到票后,终于可以回家了。2月3日晚上提前一个小时到了上海火车站,平时提前这么多时间应该是足够了,但那天显得非常得少。地铁直接到北广场的出口被封了,南广场上搭起了几个临时候车棚,到处都是人,上厕所都排起了长队。找不到候车室,赶紧问人,经人指点进了以前停车用的地下室,发现我要乘的那趟车的进站队伍已排得看不见头尾。我插到队伍里,一点点向前跟着挪动了半个小时才到了站台上。

这趟车是从上海始发至阜阳的,火车开动时,车内已经站满了人。和周围的人一聊天,一打听,原来这一节车箱里基本上都是因为买不到回阜阳的票而买了到无锡票的。大家都在说,但愿到了无锡没人能上得了车,把位子要回去。到了吴锡后,看到站台上已排起了长队,但是进得了车的只有一对夫妻,他们花钱让小红帽搬东西,小红帽直接带他们插队进了队伍的最前头。他们上了车后,后的人都上不了了。一开镇定排队上车的人,一下子骚动起来,在站台上乱跑,但是火车还是无情的开了。去年从老家回上海时,我也遇到了这样的情况,买到了票,却上不了车。现在终于明白了,那正是因为好多人不下车造成的。而我今年,也做了一次坏事,害了一个人不能上车。没有办法,这个时候已经管不了那么多了。

为了上厕所,我提前一个小时向车箱一头的厕所挪过去。短短的十米,我却挤了近半个小时,不停地道歉,求人让一下,配合一下,最终才在人堆里硬挤了过去。有不少人蹲在地上,尤其是一些女孩子和年纪比较大人。但是蹲下明显会占据更多的面积,我又不好从人家身上跨过去,所以要不停说服别人站起来一下,让一下。其实蹲在下面,空气不好,身体不能伸展,呼吸也不畅,对身体很不好,但相对于双腿,他们还是选择委屈肺。厕所里的情况看得见闻得到,就不说了。出了厕所,本想先等一会儿再回去的,厕所旁边的人就意见大了,推着我说,你怎么还不走。我只好向前再挤。好在过来的时候,人家都认得了我,回去的时候,他们都不想让我多留,占他们的空间,于是就一路把我推了回去。

火车停在常州的时候,终于发生了爬窗事件。一个老农看从门上车无望,便走到我后面一排座的车窗旁,一下子把车窗拉开,先把化肥口袋向里一塞,跟着自己就爬了进来。这个窗口对于车外的人就是希望之门。女孩子放弃了矜持,老人家不顾身子,都向里冲,后面的小伙子更是在后面推人,推进了别人,自己好跟着进去,一片混乱。进来的人没有地方站,就踩在桌子上椅子上,甚至于是别人身上,还不停地叫着帮忙向里走走,让一让。里面的人七嘴八舌地大吼快关窗户,可是早已经关不上了。挤上来十来个人后,终于有车站的管事的人来了,在外面把人拉开。一个小伙子看着别人上了车,自己没有上成,把火全发在刚才挤进去的人身上,一边大骂,一边流着泪,还向窗里人猛捶。被打到的人在里面没有地方站,已是心情很不爽,被这么一打骂,红了眼,要伸头出去打。要不是车站的工作人员强行关上窗,真不知道要如何收场。

这一次再想上厕所是彻底没有希望了,所以无论里面如何燥热口渴,我就是不喝那瓶可乐。民工流高峰期,再也不能乘到阜阳的车了。不知道要到什么年月,过年回家才不是一件痛苦的事情。

Share/Save/Bookmark

从spring 2.5的文档里直接抄下的来配置文件,来配置数据库连接池和hibernate,结果发现运行一段时间后程序就会在查询数据库的地方卡死,而且日志里并没有打印现hibenrate的sql,问题到底发生在什么地方呢?我打开jconsole,连接到程序上一看,发现好多线程被阻塞了,而且都阻塞于pool.getConnection(),看来是DBCP出了问题。后来在网上查了一会,找到hibernate邮件列表上的一段讨论,原来hibernate开发人员认为DBCP设计得不好,BUG多,文档少,所以就不再提供对DBCP的支持了,要用数据库连接池就得用c3p0。看来hibernate每次用完连接都不还给连接池的。我也不想去找如何配置C3P0了,反正生产环境用的肯定是jboss的通过JNDI取到的数据源。干脆让tomcat来管理数据库连接池吧,让spring通过jndi来找到它。在tomcat里配置数据源很简单,官方网站上有详细说明。简单说把下面这段xml复制到tomcat安装目录下的conf/context.xml里就可以了:

<Resource name=”myDataSourceName” auth=”Container” type=”javax.sql.DataSource”
maxActive=”100″ maxIdle=”30″ maxWait=”10000″
username=”root” password=”" driverClassName=”com.mysql.jdbc.Driver”
url=”jdbc:mysql://localhost:3309/mydatabase” removeAbandoned=”true” removeAbandonedTimeout=”10″ logAbandoned=”false” />

上面这段Resource元素很容易理解,关键就是removeAbandoned和removeAbandonedTimeout这两个属性,它们是告诉DBCP把被遗弃的连接删掉,以及被遗弃多久才删除。hibernate就是那个常常遗弃连接的家伙。

Share/Save/Bookmark

January 29th, 2008春节购票记

又是一年春节到,买票难,痛苦。去年春节前,在网上联系到一个黄牛,花了150买了一张30块的车票,而且车次很差,车内很脏,很臭,但为了回家过年,也只好忍着了。今年得提前做好准备了。1月26日在上海可以买到回家的票,25日晚上又正好开公司年会。吃完喝完回来经过火车票代售点的时候,吓了一跳,这才晚上十点钟就已经排了五十来人的队了,而且外面还下着小雪。如果去排队,就算排到明天早上估计五十多名也是没有希望的了。于是我从队头开始一个一个人问,看有没有人可以帮我代买一张票的,我愿出多出150块来买票。终于找到一个二十来岁的男子,就把手机号留给了他。

第二天早上,在睡梦中被手机惊醒,那兄弟没有买到直接回家的票,但是买到了同一火车的近几站的票,不管那么多了,只要能上车就行了,上车再说吧。我急忙穿上衣跑去售票点,却忙了带手机,跑到地方发现买票大队已有大约三百来人了。但是我没有手机,找不到那个人,没有看到他。没有办法,我只好又赶回住处拿手机,已人两个未接电话。我赶紧打电话过去解释,但是已经晚了,他代买的票已经卖给了别人了。郁闷。

唉,火车票真难买呀,先不买了,等等再买黄牛票吧。本已为没有多少希望买到票了,1月27日下午却又突然接到那哥们的电话,原来这家伙自己怕自己买不到票,也让别人帮他带了票,结果自己买到了票,别人也带到了票,他自己搞到两张票,正需要脱手一张,于是就找到了我。我说,这次我不能再出高价买了,他说,你看着我排了十几个小时队的份上总得给些辛苦费吧!好吧,我多给了他50。终于拿到了宝贵的火车票!

每年回家都这么困难,真不知道这样的春节还要过多少个?

这两天全国雪灾,好多火车晚点停运,只怕有票都不一定能回得去了,再看看吧。

Share/Save/Bookmark


第8 页 共15页« 首页...«678910»...末页 »
© 2007 涂0实验室 | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress