Externalizable接口实现以后...........

2008 六月 04 , 11:02下午
in category 原创空间 by BruceJini

java 串行化有两个比较普遍的接口,一个是Serialable,一个Externalizable,前者直接恢复二进制数据,后者会对对象重组。具体细节可以看看下面的代码<BR><BR>

package serial;

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;


public class TestExternalizable implements Externalizable{
String name;
public TestExternalizable() {
System.out.println("1");
// TODO Auto-generated constructor stub
}
public TestExternalizable(String name) {
System.out.println("2");
// TODO Auto-generated constructor stub
System.out.println("name:" + this.name);
this.name = name;
System.out.println("name:" + this.name);
}
public static void main(String[] args) {

TestExternalizable test = new TestExternalizable("brucejini");
FileOutputStream out;
try {
out = new FileOutputStream("d:/dd.sys");
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(test);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileInputStream in;
try {
in = new FileInputStream("d:/dd.sys");
ObjectInputStream ois = new ObjectInputStream(in);
TestExternalizable testin = (TestExternalizable) ois.readObject();
// TestExternalizable test = new TestExternalizable("");
// test.readExternal(ois);
System.out.println(testin.name);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
this.name = (String)in.readObject();
// System.out.println(test.name);
}

public void writeExternal(ObjectOutput out) throws IOException {

// TODO Auto-generated method stub
out.writeObject(name);
}



<CODE><XMP>

   运行后的结果:

2
name:null
name:brucejini
1
brucejini


可以看出,实际上在尝试反串行化之时,对象是被重新装配起来啊的,基本上可以看到这个过程。自定义串行化,当然,如果属性对象存在的话,也会在父对象之前执行,也还可以去试试

[评论(0)]

发现一个很不错的基于JDBC的数据库管理工具

2007 六月 13 , 01:28下午
in category 原创空间 by BruceJini

见 http://www.squirrelsql.org/#installation 。java开发中的数据库都支持,驱动管理,JDBC中的所有API返回信息浏览,等等。就是SQL 的语法提示会与输入法冲突,好像还不能改。







[评论(0)]

架构师书单 2nd Edition

2007 五月 30 , 02:57下午
in category Java摘录 by BruceJini

   作者:江南白衣,原文出处: http://blog.csdn.net/calvinxiu/archive/2007/03/06/1522032.aspx,转载请保留。

   为了2007年的目标,列了下面待读或重读的书单。 
   "其实中国程序员,现在最需要的是一张安静的书桌。",的确,中国架构师大多缺乏系统的基础知识,与其自欺欺人的宣扬"读书无用,重在实践变通,修身立命哲学书更重要",把大好时间用来追逐互联网上的片言只语,不如直面缺陷,系统的学习一次。

   一、Software Architecture篇

     这个领域没有什么"畅销书",可能读者中本来就是开发设计人员与项目经理占了多数,真正定位为架构师而且做的也是架构师工作的不多吧,你懂的尽是偏僻的人生。

   1.软件架构入门 
《Large-Scale Software Architecture --大型软件体系结构:使用UML实践指南》
   
现代架构师的入行指南,从什么是架构和架构师一直到以构件为粒度的大型系统架构UML实例。

 

 2. 软件架构进阶 

《Software Architecture in Practice,2nd Edition软件构架实践(第2版)》

   第一版是第九届JOLT作品,一本被引用很多的架构书。

《Documenting Software Architectures 软件构架编档》

   第13届JOLT大奖作品,捕获架构的过程,徐昊推荐。

《Applied Software Architecture 实用软件体系结构》

   另一本被引用很多的架构之书。

《The Art of Software Architecture
软件体系结构的艺术》

    薄薄的一本,上面几本的理论抽象与薄化。




 

 

二、RUP/UML 篇

RUP、UML、4+1视图始终是架构师界最通用的东西,寻找一种向世界妥协的方式。

 1. RUP 文档
《The Rational Unified Process:An Introduction.3rd Edition RUP导论(第3版)》是RUP2003文档的缩略版,在啃文档细节前可以先拿中文版来翻一下。
   但公司里总是充满对RUP的误解,《The Rational Unified Process Made Easy:A Practitioner's Guide to the RUP
Rational统一过程:实践者指南》是排除各种误解的RUP实施指南。

  2. UML2工具书
《UML2 ToolkitUML2.0工具箱》或者《UML精粹第3版
UML Distilled 3rd》都不错,后一本略薄。

  3.《UML和模式应用(第3版)--Applying UML and Patterns 3rd》
   UML+RUP作的OOAD过程。


三、特定领域篇

    开发人员有GOF23 Pattern,架构师同样也有架构师的Pattern。不同领域的架构师需要不同的知识。
1. 公共领域
《Domain-Specific Application Frameworks 特定领域应用框架:行业的框架体验》
  ozzzzzz推荐,介绍了30个特定领域特定框架的设计。我自己最喜欢看人家的设计与思考。

《Object Oriented Reengineering Patterns软件再造:面向对象的软件再工程模式 》
  逆向工程与再工程的模式,架构师整天都要和旧系统打交道,接手一个架构师已跑路,文档不全的系统开发2.0版本。

《Head First Design Patterns》 
  最好的GOF23经典设计模式阐释,适合被[GAMMA95]折磨的架构师拿来复习,中文版即将发行。

 




2. Java EE领域
 
  《Patterns of Enterprise Application Architecture 企业应用架构模式》
    
 Martin Fowler经典,企业应用各Layers上的模式。   
  

  《Effective Enterprise Java
中文版》    
      Neward, Ted作品,作者学贯东西(.Net与Java),像写Blog一样,每一页里面都有大量的信息。

  




3. EAI/SOA领域 
《Enterprise Integration Patterns --企业集成模式:设计、构建及部署消息传递解决方案》
 


4. 网络与后台服务编程领域
《Pattern-Oriented Software Architecture, Volume 2 --面向模式的软件体系结构 卷2:用于并发和网络化对象的模式》

《Pattern-Oriented Software Architecture, Volume 3
--面向模式的软件体系结构卷3:资源管理模式》

    著名的POSA2与POSA3。
 
 

四、闲书篇

《Code Complete 2 代码大全2》 
   一本你教育小弟时的代言人。

《The Pragmatic Programmer 程序员修炼之道:从小工到专家》 
   一本你启发小弟的代言人。

《The Art of Unix Programming --UNIX编程艺术》
 

 

 

五、高效读书心得

   刚好Head First系列开头都有一段教人如何读书的话,再加工整理如下:

1.尽量阅读中文版
  虽然有人英文很强,有的翻译很差,但AnyWay 中文阅读与理解的时间,略读与快速定位的速度还是要快一些。
 
2.即时批注、总结笔记与交流
  虽然爱书,但发现最有效的读书方式还是不断的制造脂批本,读书时在重要的文字下划线,把自己的心得写在页旁。
  在明天复习一次批注,最好可以有空重新整理笔记,或者拿来与人讨论。 
 
3.大量思考或重复记忆
  看书最郁闷的事情就是看完之后脑袋空空了。技术书还好点,虽然看的时候可能很辛苦,但就像学会了骑单车,之后再骑的时候总是会的;而偏设计与管理的书,最容易的事情就是看的时候很快,看完没什么留下到实践中。
  所以,我们不能以看小说的速度来看设计书,要寻找思考的机会,思考是最好的记忆。
  又或者,大量的重复记忆,重复多遍直到无意识的记忆。 
 
4.人体工学
  那些见缝插针的时间与地点不是看这个书单的好地方。
  环境不要有电视,音乐等强输入源,而微风阳光鸟语等弱输入源则有助活跃大脑。
  看书时大量的喝水。
  如果发现自己的大脑已经疲累,已经在浮光掠影的翻看,就要休息。
  留给大脑消化的时间,看完书不要接着看其他有难度的书或事情。


[评论(1)]

一个主线程对n个简单子线程的控制 [2]

2007 五月 15 , 05:37下午
in category 原创空间 by BruceJini

上一个程序其实是以一种“轮询”来控制线程调度的,这样不是个好办法,主线程轮询占用了不少资源,即使存在时间间隔。小程序还行,程序大了,线程执行时间和线程数量越多,消耗就越大。

相对来说,使用“事件”驱动就是个比较好的选择了。再看看下面用事件实现同样的调度:

ThreadManager.java import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * 该类用来管理所有线程,map和在所有线程和此类对象之间是需要同步的. * 所有方法之间需要按照一定的流程执行 * */ public class ThreadManager { private Thread[] li; private Map map; private ThreadGroup gup; private Map users; private static String threadname = Constants.THREAD_NAME;//线程名常量 /** * @param x * 创建的线程个数 */ public ThreadManager(int x) { // 初始化线程列表 li = new Thread[x]; map = Collections.synchronizedMap(new HashMap(x)); gup = new ThreadGroup("register"); //线程组名 users = new HashMap(); // 创造n个注册处理线程 for (int i = 0; i < x; i++) { li[i] = new RegisterThread(gup, threadname + String.valueOf(i), map); } } /** * @return * @throws InterruptedException */ public Map first() throws InterruptedException { for (int i = 0; i < li.length; i++) { RegisterThread th = (RegisterThread) li[i]; th.start(); } //主线程在完成启动所有子线程后阻塞 synchronized (this) { this.wait(); //主线程被唤醒后并不马上执行,等待最后一个注册线程完成 if (isAllThreadWaiting()) { Thread.sleep(10); } } return map; //返回中途的结果集 } /** * 线程再度执行的方法 * @param result * @return * @throws InterruptedException */ public Map second(Map result) throws InterruptedException { map.putAll(result); //再度执行的线程可能需要新的待处理数据,这里假设还是同一个map for (int i = 0; i < li .length; i++) { //唤醒所有等待中的线程 synchronized (li [i]) { li [i].notifyAll(); } } //同样的,主线程停止等待返回结果 synchronized (this) { this.wait(); } return map; //假设继续执行的线成还是处理数据map } /** * 判断线程队列中是否仅有当前线程未进入等待状态 * * @param me * @return */ public boolean isAllOtherThreadWaiting(Thread me) { for (int i = 0; i < threadlist.length; i++) { if (threadlist[i] != me && threadlist[i].getState().equals(Thread.State.WAITING) != true) { return false; } } return true; } /** * 判断线程队列中是否所有线程进入等待状态 * * @param me * @return */ public boolean isAllThreadWaiting() { for (int i = 0; i < threadlist.length; i++) { if (threadlist[i].getState().equals(Thread.State.WAITING) != true) { return false; } } return true; } /** * 判断当前manager所在线程是否waiting * * @return */ public boolean isManagerThreadWaiting() { if (Thread.currentThread().getState().equals(Thread.State.WAITING)) { return true; } return false; } }

RegisterThread.java import java.io.IOException; import java.util.Map; public class RegisterThread extends Thread { private Map map; private ThreadManager manager; public RegisterThread(ThreadGroup gup,String name ) { super(gup,name); } public RegisterThread(ThreadGroup gup,String name,Map map,ThreadManager manager){ this(gup,name); this.map = map; this.manager = manager; } public void run() { //do something with map here map.put(Thread.currentThread().getName(), "数据"); //暂停等待用户输入验证值并重新唤醒本线程 if (manager.isAllOtherThreadWaiting(currentThread())) { synchronized (manager) { manager.notify(); } } //然后让注册线程阻塞 synchronized (this) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //do something here again //递交表单 map.put(Thread.currentThread().getName(),"新数据"); if (Thread.activeCount() == 1 ) { synchronized (manager) { manager.notify(); } } } } 手写的代码比较乱。总的来说这个原理就是由主线程启动所有子线程,主线程然后等待,好比老板叫手下干活,布置好任务,然后自己去睡觉。每个最后一个子线程如果发现自己是最后一个,就把主线程唤醒,好比最后一个干活还没趴下的手下在昏倒前把老板唤醒了,注意,这时最后一个手下是不能倒的,不然就没人叫醒老板了,全倒了你的程序就永远长眠了。老板醒了,等到最后一个手下也躺了,他一次把所有人都叫醒,并给他们新任务,注意要等最后一个也要倒了才叫,不然就不是都叫醒了,嘿嘿。老板又睡了,这时候所有的手下都陆续累死了,最后一个快死的把老板叫醒了,老板得到他们的劳动成果,找用户领赏钱去了。上面的过程基本就是这样。











[评论(1)]

一个主线程对n个简单子线程的控制

2007 五月 11 , 09:53上午
in category 心情故事 by BruceJini

先看一个简单的例子,主线程控制所有的子线程调度:


ThreadManager.java import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * 该类用来管理所有线程,map和在所有线程和此类对象之间是需要同步的. * 所有方法之间需要按照一定的流程执行 * @author hwx * */ public class ThreadManager { /** * Logger for this class */ private Thread[] li; private Map map; private ThreadGroup gup; private Map users; private static String threadname = Constants.THREAD_NAME;//线程名常量 /** * @param x * 创建的线程个数 */ public ThreadManager(int x) { // 初始化线程列表 li = new Thread[x]; map = Collections.synchronizedMap(new HashMap(x)); gup = new ThreadGroup("register"); //线程组名 users = new HashMap(); // 创造n个注册处理线程 for (int i = 0; i < x; i++) { li[i] = new RegisterThread(gup, threadname + String.valueOf(i), map); } } /** * 发送请求并返回包含所有图片的数据 * @return * @throws InterruptedException */ public Map first() throws InterruptedException { for (int i = 0; i < li.length; i++) { RegisterThread th = (RegisterThread) li[i]; th.start(); } // 等待所有线程完成部分进度,并且将结果写入同步的map中,下面的代码通过验证结果集来判断是否所有的线程都已经完成一定的进度 while (map.size() < li.length) { Thread.currentThread().sleep(100); } return map; //返回中途的结果集 } /** * 线程再度执行的方法 * @param result * @return * @throws InterruptedException */ public Map second(Map result) throws InterruptedException { map.putAll(result); //再度执行的线程可能需要新的待处理数据,这里假设还是同一个map for (int i = 0; i < li.length; i++) { RegisterThread th = (RegisterThread) li[i]; th.resume(); //重新启动线程 } while (gup.activeCount() > 0) { //这通过判断线程组来决定是否所有线程都终结 Thread.currentThread().sleep(1000); } return map; //假设继续执行的线成还是处理数据map } }

RegisterThread.java import java.io.IOException; import java.util.Map; public class RegisterThread extends Thread { private Map map; public RegisterThread(ThreadGroup gup,String name ) { super(gup,name); } public RegisterThread(ThreadGroup gup,String name,Map map){ this(gup,name); setMap(map); } public void run() { //do something here map.put(Thread.currentThread().getName(), "数据"); //暂停等待用户输入验证值并重新唤醒本线程 this.suspend(); //do something here again //递交表单 map.put(Thread.currentThread().getName(),"新数据"); this.stop(); } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } } 代码的数据仅仅为一个同步Map类,调度判断使用的是"轮询"方式,轮询数据和线程组,当然还有更加好的处理方式。这种情况在web开发中比较常见,比如你必须要等待n个线程都完成对数据的处理才统一给客户端一个web页面。



[评论(0)]

[Ljava.lang.String; cannot be cast to java.lang.String 异常

2007 五月 08 , 03:55下午
in category 原创空间 by BruceJini

今天遇到一个异常java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.Strings.原因是调用了servlet中HttpServletRequest.getParameterMap(). Map paras = arg0.getParameterMap(); 后来才发现这个返回的Map中的键值对为<String, String[]>,并且此Map同步锁别占用,不能修改其已存在数据,否则抛出异常:java.lang.IllegalStateException: No modifications are allowed to a locked ParameterMap 如果你需要动态的得到所有post参数,还需要一个另外的Map来putall.当然也可以在调用的时候取其数组的[0],不过容易发生误会。







[评论(0)]

安全的取代stop()终止线程

2007 五月 01 , 09:06上午
in category 原创空间 by BruceJini

Thread.stop()已经被宣告为过时,因为它突然的杀死线程会释放所有的对象锁。这可能出现不可预料的错误,所以我们需要谨慎使用,相传有一种安全的取代方法:
public class AlternateStop extends Object implements Runnable {

	private volatile boolean stopRequested;

	private Thread runThread;

	public void run() {

		runThread = Thread.currentThread();

		stopRequested = false;

		int count = 0;

		while (!stopRequested) {

			System.out.println("Running ... count=" + count);

			count++;

			try {

				Thread.sleep(300);

			} catch (InterruptedException x) {

				Thread.currentThread().interrupt(); // reassert

			}

		}

	}

	public void stopRequest() {

		stopRequested = true;

		if (runThread != null) {

			runThread.interrupt();

		}

	}

	public static void main(String[] args) {

		AlternateStop as = new AlternateStop();

		Thread t = new Thread(as);

		t.start();

		try {

			Thread.sleep(2000);

		} catch (InterruptedException x) {

			// ignore

		}

		as.stopRequest();

	}

}
代码摘自《java Thread programming》,其设定了一个标示变量来控制线程,并且使用sleep()和interrupt()来停止正在执行中的线程。但是这到底和stop()有什么区别呢?假如两者都在同步块中执行,一个会悄悄的释放同步锁,一个会抛出异常,但到底怎么来处理,实在是没遇到过这种实际情况.......









[评论(1)]

关于定时调度的一个简单实现

2007 四月 22 , 01:17上午
in category 原创空间 by BruceJini

java API提供了一个计时器框架,简单的例子是这样的:

public class EggTimer {
    private final Timer timer = new Timer();
    private final int minutes;
    public EggTimer(int minutes) {
        this.minutes = minutes;
    }
    public void start() {
        timer.schedule(new TimerTask() {
            public void run() {
                playSound();
                timer.cancel();
            }
            private void playSound() {
                System.out.println("Your egg is ready!");
                // Start a new thread to play a sound...
            }
        }, minutes * 10 * 1000);
    }
    public static void main(String[] args) {
        EggTimer eggTimer = new EggTimer(2);
        eggTimer.start();
    }
}

以上代码来自IBM的网站,一个煮蛋定时器,就是煮两分钟蛋然后plausound.可以看出来这个框架的结构:主线程也就是Timer所在的线程负责计时,等到时间达到条件,启动新的线程即Task线程。当然这是比较简单的例子,复杂的情况还要另想办法。

现在我假如不用它这个,What,s the plan?。想达到按时调用的情况大概有两种思路(可能还有其它),一种就是所谓的“轮询”,负责控制时间的线程不断的判断自己是否满足执行条件,利用时间变量来做,整个运行的过程中程序不断的做判断,直到过了一段时间,条件达到了。显然这是一种很直观但是很傻的方法。另外一种就是利用线程的等待或休眠来做,这样cpu是不要做那些判断的,停多少时间的事情因该交给了更底层的实现,这个我也不清楚,可能是CPU直接控制的。在JDK没有计时器框架以前可能就是这样做的。我自己做了个,每隔一定时间执行任务:

 class Timer extends Thread{
		int refreshtime;
		Object target;
		public Timer(int refreshTime,Object target) {
			this.refreshtime = refreshTime;   //间隔时间
			this.target = target;             //调度任务所在的对象
		}
		@Override
		public void run() {
			System.out.println("now start time recoding....... ");
			try {
				
			sleep(1000);  //等待一小段时间以保证主线程进入阻塞状态
			
			while(true){
				synchronized (target) {
					target.notify();     //等待中的线程开始运行,下一轮计时期也同时开始
				}
				sleep(refreshtime);     //间隔休眠
			}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

这个类可以这样调用:

		Thread timerecoder = new Timer(refreshtime,this);  
		timerecoder.start();     //启动计时线程
		
		while(true){
			synchronized (this) {
				this.wait();	//阻塞当前线程

				// do something here	

		}
		}

任务所在的线程启动了计时线程,这个和计时器框架相反,他的因该好点,这里就不改了。大概就是任务线程阻塞,然后时间条件满足就被唤醒。中间需要注意对象锁的争用,在线程sleep的时候它会保持对象锁的状态,所以不能把它放到同步块中,如果不释放同步锁而休眠,你的任务线程也会等待,因为同步锁没有交给它,这就影响任务的执行时间,完全不对了。

总的来说,要自己实现计时调度还是比较复杂的,因为涉及到同步问题,稍不留神就错了。上面的sleep就是个例子,可以把它放到上面的同步块中,时间就合单线程的效果一样了。



[评论(0)]

我的监视页面域的页面

2007 四月 10 , 09:45下午
in category 原创空间 by BruceJini

如下 <%@page import="java.io.PrintWriter"%> <%@page import="java.util.Enumeration"%> <%@ page language="java" contentType="text/html; charset=utf8" pageEncoding="utf8"%> <% //页面调试 Enumeration appnames = application.getAttributeNames(); Enumeration sesnames = session.getAttributeNames(); Enumeration reqnames = request.getAttributeNames(); %> <div style="border:1px solid red;padding:20px;width:90%;margin: 20px;text-align: left;overflow: scroll"> <h3>web context</h3> <center>############################ application #######################################</center> <br> <% while (appnames.hasMoreElements()) { String name = (String) appnames.nextElement(); %> <b><%= name %>:</b> <%= application.getAttribute(name) %> <br> <%}%> <center>############################ session #######################################</center> <br> <% while (sesnames.hasMoreElements()) { String name = (String) sesnames.nextElement(); %> <b><%= name %>:</b> <%= session.getAttribute(name) %> <br> <%}%> <center>############################ request #######################################</center> <br> <% while (reqnames.hasMoreElements()) { String name = (String) reqnames.nextElement(); %> <b><%= name %>:</b> <%= request.getAttribute(name) %> <br> <%}%> </div> 可以include到每个页面的公共部份,如footer的最下面就挺好,可以在开发中监视每个作用域。





[评论(0)]

一个重要的EcodeFilter经验

2007 四月 02 , 08:24下午
in category 原创空间 by BruceJini

   今天做了EcodeFilter来解决乱码问题,可是却一直不起作用,最后终于发现问题所在,估计很多人也遇到了。首先来看一个EcodeFilter的实现,很简单的:

   
      public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		
		//arg0.getParameter("name");

arg0.setCharacterEncoding("utf-8");

//String name= new String(arg0.getParameter("name").getBytes("utf-8"),"utf-8"); //System.out.println(name);

arg2.doFilter(arg0, arg1); }
   这样配置的EcodeFilter是起作用的,把第一部分注释去掉就能看到效果。但这时我们把第一部分注释也去掉会出现完全相反的结果了!?不信的朋友可以试试,出现乱码了。原因很简单,第一次从request中getParameter()的时候,所有的参数都会初始化,这里包括“name”,当然还有其它的。初始化的编码默认为“iso8859_1”,如果初始化之前你没有设置编码就不会起作用的,这点很重要,所以EcodeFilter最好放在最前面,保证是在初始化参数以前。不然,嘿嘿,你的乱码问题是解决不了的哦。









[评论(0)]

标签库的原则

2007 四月 02 , 12:29下午
in category Java摘录 by BruceJini

        标签库必须坚持“不从自定义标签中生成HTML代码”的设计抉择,而应该使自定义标签把动态值填充到HTML的模板中。不管你怎么设计,记住HTML编辑者是无法看见你自动生成的HTML代码的。

        很多JSP标签库都是遵循这一原则,如JSTL,反面的例子就是.net了,他的很多控件(标签库)实践程度不高就是在其中嵌入了HTML代码,也许,它(微软)总是认为HTML开发人员会喜欢他自动添加的HTML标签,如"<td>....</td>",可是他没想过如果他们不想要这个HTML标签了,他们不得不为此更换控件(标签库).............

 

六种事物属性

2007 三月 25 , 12:00上午
in category Java摘录 by BruceJini

一个事务属性可能有下面的属性之一:

☆ Required

☆ RequiresNew

☆ Mandatory

☆ NotSupported

☆ Supports

☆ Never

Required
如果客户端正在一个运行的事务中调用一个企业Bean的方法,这个方法就在这个客户端的事务中执行。如果客户端不关联一个事务,这个容器在运行该方法前开始一个新的事务。

Required属性在许多事务环境中可以很好的工作,因此你可以把它作为一个默认值,至少可以在早期开发中使用。因为事务的属性是在部署描述符中声明的,在以后的任何时候修改它们都很容易。

RequiresNew
如果客户端在一个运行的事务中调用企业Bean的方法,容器的步骤是:

1.挂起客户端的事务

2.开始一个新的事务

3.代理方法的调用

4.方法完成后重新开始客户端的事务

如果客户端不关联一个事务,容器运行这个方法以前同样开始一个新的事务。如果你想保证该方法在任何时候都在一个新事物中运行,使用RequiresNew属性。

Mandatory
如果客户端在一个运行的事务中调用企业Bean的方法,这个方法就在客户端的事务中执行。如果客户端不关联事务,容器就抛出TransactionRequiredException 异常。

如果企业Bean的方法必须使用客户端的事务,那么就使用Mandatory属性。

NotSupported
如果客户端在一个运行的事务中调用企业Bean的方法,这个容器在调用该方法以前挂起客户端事务。方法执行完后,容器重新开始客户端的事务。

如果客户端不关联事务,容器在方法运行以前不会开始一个新的事务。为不需要事务的方法使用NotSupported属性。因为事务包括整个过程,这个属性可以提高性能。

Supports

如果客户端在一个运行的事务中调用企业Bean的方法,这个方法在客户端的事务中执行,如果这个客户端不关联一个事务,容器运行该方法前也不会开始一个新的事务。因为该属性使方法的事务行为不确定,你应该谨慎使用Supports属性。

Never

如果客户端在一个运行的事务中调用企业Bean的方法,容器将抛出RemoteException异常。如果这个客户端不关联一个事务,容器运行该方法以前不会开始一个新的事务。

 

欧罗巴 Europa

2007 三月 22 , 12:17上午
in category 心情故事 by BruceJini

欧罗巴是木星的第六颗已知卫星,是17颗木星卫星中体积较大的一颗,据科学推测,它是太阳系中有可能存在生命的卫星之一。[Read More]

学习了一个月的Spring,感觉他的文档太少了

2007 三月 17 , 11:06下午
in category 心情故事 by BruceJini

   Spring确实不错,用起来简单,单例模式什么的都能自己实现,不用再花时间做重复工作。很多东西用起来也简单,但是感觉文档太少了,网上的文章都是些入门的,论坛总是解决不了我的迫切需要,refrences只做了些主要的说明,Rod的那本书还算有些内容,不过很大部分是在说他的经验。,按照spring的思想,每一种方案都会给你几种实现的选择,细节部分的疑问都只有自己试。全盘的学习Spring其实就是在了解j2ee的基本架构,J2EE到底需要做到什么的疑问也会慢慢得到解答,加上Rod的那本without ejb实在是入门的好方法。

如何取得Spring启动时加载的Context

2007 三月 14 , 11:08上午
in category 原创空间 by BruceJini

在web.xml中声明 <servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/beans.xml</param-value> </context-param> 即可以加载Spring的context,那么如何取得这个context呢?遍历ServletContext有以下结果 org.apache.catalina.jsp_classpath javax.servlet.context.tempdir org.springframework.web.context.WebApplicationContext.ROOT org.apache.catalina.resources org.springframework.web.servlet.FrameworkServlet.CONTEXT.Dispatcher org.apache.catalina.WELCOME_FILES 其中“org.springframework.web.context.WebApplicationContext.ROOT”就是context的全局变量名。当然,有个更简单的办法,就是用Spring的工具类WebApplicationContextUtils WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)