??xml version="1.0" encoding="utf-8" standalone="yes"?> 一、简单的用ApplicationContext做测试的?获得Spring中定义的Bean实例(对象).可以? ApplicationContext ac = new ClassPathXmlApplicationC 如果是两个以? 或者用通配W? classpath:前缀是不需要的,默认是指项目的classpath路径下面; 对于FileSystemXmlApplication 1.没有盘符的是目工作路径,即项目的根目? 如果要用classpath路径,需要前~classpath: public class HelloClient { protected static final Log log = LogFactory.getLog(HelloClient.class); public static void main(String[] args) { // 用classpath路径 // ClassPathXmlApplicationC // 用文件系l的路径,默认指项目的根\?br />// ApplicationContext factory = new FileSystemXmlApplication // 使用了classpath:前缀,q样,FileSystemXmlApplication // 不加file前缀
RegisterDAO registerDAO = (RegisterDAO)ac.getBean("RegisterDAO");
ApplicationContext ac = new ClassPathXmlApplicationC
ApplicationContext ac = new ClassPathXmlApplicationC
二、ClassPathXmlApplicationC
如果要用绝对\?需要加上file:前缀表示q是l对路径;
默认表示的是两种:
2.有盘W表C的是文件绝对\?
// Resource resource = new ClassPathResource("appcontext.xml");
// BeanFactory factory = new XmlBeanFactory(resource);
// ApplicationContext factory = new ClassPathXmlApplicationC
// ApplicationContext factory = new ClassPathXmlApplicationC
// ApplicationContext factory = new ClassPathXmlApplicationC
// ApplicationContext factory = new FileSystemXmlApplication
// ApplicationContext factory = new FileSystemXmlApplication
// ApplicationContext factory = new FileSystemXmlApplication
ApplicationContext factory = new FileSystemXmlApplication
IHelloWorld hw = (IHelloWorld)factory.getBean("helloworldbean");
log.info(hw.getContent("luoshifei"));
}
}
]]>
JavaGUIE序发布分类
1) AppletQ可以嵌入到览器中Q通过|页的方式展C给用户
2) application Q有两种发布方式
ü 打包成jar包通过bat的方式运行,或者通过W三方Y件打成exe(后箋会再详细介绍)
ü 通过Java Web Start的方式发布到服务器端Q通过JNLPq行
相对来说W二U方式可能更好一些,免除了更新的ȝ?/span>
用applet或者jws的方式发布,大部分都需要数字签名?br />
Z么要{
其实{不是必须的,如果你的E序只是单纯的绘图,昄Q只要不讉K|络资源也不讉K本地文gQ是不用{的,
但是如果要访问本地或|上资源必ȝ名,
比如d本地文g或者访问数据库Q这是由java的沙机制决定的Q即jvm内部有一l安全检查规则,要通过查之后才能访问特定资源?/span>
如果要突破这个规则,可以有两个方?
1) 修改jre权限文g如下
java.policy为grant {
permission java.security.AllPermission;
};
一般权限文件的目录如下C:"Program Files"Java"jre6"lib"security
但是修改每个客户端的权限文gQ无Z旉q是操作上都是很ȝ的?/span>
2) {Q意思就是告诉用Pq个E序是谁发布的,是不是能信QQ如果客L(fng)定,okQ这个applet或者jws可以访问外部资源了?br />
如何{
1)首先保你已l完全安装了Java2的环境,有keytool工具Q它位于JDK的bin目录下。这一般不会有问题?/span>
2)到Dos状态下Q进入你需发布应用E序的jar包所在的目录Q运行下面这句话
keytool -genkey -keystore myKeystore -alias jwstest -validity 1000
它将会提CZ输入用户名、密码等Q按照提C随便输入即可,不输入直接回车即可,
但一定要C密码。运行结束它?yu)会在当前\径下创徏名ؓmyKeystore的文件?/span>
3)如果你想查看一下刚才生成的myKeystore文g的内容,可以使用下面q句话:
keytool -list -keystore myKeystore
昄出来应该cM如下Q?br />
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry:
jwstest, Tue Nov 23 19:29:32 PST 2001, keyEntry,
Certificate fingerprint (Test):
C3:A9:CD:F3:D3:AC:4D:3F:3C:5B:AF:9E:CF:0D:46:5C
4)对你需发布应用E序的jar包进行签名,q行下面q句话:
jarsigner -keystore myKeystore yourtest.jar jwstest
其中yourtest.jar是你的jar包名Q你需要修改它Q别的就不必修改了?br />
q行时会提示你输入密码,是你刚才在生成myKeystore文g时设定的密码?br />
如果有很多jar包怎么?/span>
在开发的q程中很可能会引用到W三方的jar包,而第三方的jar包又可能引用到其它的Q所以可能有很多的jar包,需要和applet一起发布,有两个方?br />
1) 分别打包{Q用于包比较少Q比如只??个的情况
2) ?把applet的jar包签名,让用L(fng)认访问授权,applet已经被用h权,那么可以在applet里改变安全管理器QSecurityManagerQ?br />
只需要承SecurityManagerc,创徏自己的安全管理器c,然后覆盖checkPermissionҎ(gu)Q允许访问Q何资源?br />
在applet的initҎ(gu)中调用System.setSecurityManager把安全管理器讄为我们自定义的即可?/span>
class CustomManager extends SecurityManager {
public void checkPermission(Permission perm, Object context) {
}
public void checkPermission(Permission perm) {
}
}
其它一些相兌料如?/span>
JDK中keytool常用命o
-genkey 在用户主目录中创Z个默认文?.keystore",q会产生一个mykey的别名,mykey中包含用L(fng)公钥、私钥和证书
-alias 产生别名
-keystore 指定密钥库的名称(产生的各cM息将不在.keystore文g?br />
-keyalg 指定密钥的算?nbsp;
-validity 指定创徏的证书有效期多少?br />
-keysize 指定密钥长度
-storepass 指定密钥库的密码
-keypass 指定别名条目的密?br />
-dname 指定证书拥有者信?例如Q?nbsp; "CN=sagely,OU=atr,O=szu,L=sz,ST=gd,C=cn"
-list 昄密钥库中的证书信?nbsp; keytool -list -v -keystore sage -storepass ....
-v 昄密钥库中的证书详l信?br />
-export 别名指定的证书导出到文?nbsp; keytool -export -alias caroot -file caroot.crt
-file 参数指定导出到文件的文g?br />
-delete 删除密钥库中某条?nbsp; keytool -delete -alias sage -keystore sage
-keypasswd 修改密钥库中指定条目口o keytool -keypasswd -alias sage -keypass .... -new .... -storepass ... -keystore sage
-import 已{数字证书导入密钥?nbsp; keytool -import -alias sage -keystore sagely -file sagely.crt
导入已签名数字证书用keytool -list -v 以后可以明显发现多了认证N度,q且把整个CA铑օ部打印出来?/span>
Keytool 是安全钥匙与证书的管理工?它管理一个存储了U有钥匙和验证相应公共钥匙的与它们相兌的X.509 证书铄keystore(相当一个数据库).
Keytool 是一个有效的安全钥匙和证书的理工具. 它能够用户使用数字{来管理他们自qU有/公共钥匙?理用来作自我鉴定的相关的证?理数据完整性和鉴定服务.它还能用户在通信时缓存它们的公共钥匙.
一个证书是某一实体(个h,公司{?的数字签?指出其他实体的公共钥?或其他信?的详l的?当数据被{?q个{信息被用来检验数据的完整性和真实?完整性指数据没有被修改和改,真实性指数据从Q何生和{的一方真正的传输到达.
Keytool 把钥匙和证书储存C个keystore.默Q的实现keystore的是一个文?它用一个密码保护钥?
而另外的一个工具jarsigner用keystore中的信息产生或检验Java aRchive(jar文g)中的数字{.
Keystore有两个不同的入口:
1.钥匙入口:保存了非常敏感的加密的钥匙信?q且是用一个保护的格式存储以防止未被授权的讉K.以这UŞ式存储的钥匙是秘密钥?或是一个对应证书链中公有钥匙的U有钥匙.
2.信Q证书入口:包含一个属于其他部分的单一公共钥匙证书.它之所以被UCؓ"信Q证书",是因为keystore信Q的证书中的公共钥匙真正属于证书所有者的w䆾识别.
Keystore的别?
所有的keystore入口(钥匙和信任证书入?是通过唯一的别名访?别名?不区分大写?如别名Hugo和hugo指向同一个keystore入口.
可以在加一个入口到keystore的时候?genkey参数来生一个钥匙对(公共钥匙和私有钥?时指定别?也可以用-import参数加一个证书或证书铑ֈ信Q证书.
?
keytool -genkey -alias duke -keypass dukekeypasswd
其中duke为别?dukekeypasswd为duke别名的密?q行命o的作用是产生一个新的公?U有钥匙?
假如你想修改密码,可以?
keytool -keypasswd -alias duke -keypass dukekeypasswd -new newpass
旧密码dukekeypasswd改ؓnewpass.
Keystore的?
1.当?genkey ?import?identitydb命od数据C个keystore,而当q个keystore不存在时,产生一个keystore.默认名是.keystore,存放到user-home目录.
2.当用-keystore指定?生指定的keystore.
Keystore的实?
Keytool cM于java.security包下,提供一个非常好的接口去取得和修改一个keystore中的信息. 目前有两个命令行:keytool和jarsinger,一个GUI工具Policy 可以实现keystore.׃keystore是公开?用户可以用它写一些额外的安全应用E序.
Keystoreq有一个sun公司提供的內在实?它把keystore作ؓ一个文件来实现.利用了一个keystorecd(格式)"JKS".它用单独的密码保护每一个私有钥?也用可能不同的密码保护整个keystore的完整?
支持的算法和钥匙大小:
keytool允许用户指定钥匙对和注册密码服务供应者所提供的签名算?~省的钥匙对产生法?DSA".假如U有钥匙?DSA"cd,~省{法?SHA1withDSA",假如U有钥匙?RSA"cd,~省法?MD5withRSA".
当生一个DSA钥匙?钥匙必须?12-1024位之?对Q何算法的~省钥匙大小?024?
证书:
一个证书是一个实体的数字{,指出其他实体的公共钥匙有明确的?
1.公共钥匙 :是同一个详l的实体的数字关?q有意让所有想同这个实体发生信dpȝ其他实体知道.公共钥匙用来验签?
2.数字{:假如数据已被{,q用w䆾存储在一个实体中,一个签名能够证明这个实体知道这个数?q个数据用实体私有钥匙签名ƈ递交;
3.w䆾:知道实体的方?在一些系l中w䆾是公共钥?其他pȝ中可以是从一个X.509名字的邮件地址的Unix UID来的M东西;
4.{:一个签名用用实体私有钥匙来计算某些加密数据;
5.U有钥匙:是一些数?每一个私有钥匙只能被特定的拥有该U有钥匙的实体知?U有和公共钥匙存在所有用公共钥匙加密的系l的钥匙对中.一个公共钥匙加?如DSA),一个私有钥匙与一个正的公共钥匙通信.U有钥匙用来计算{.
6.实体:一个实体可以是一个h,一个组l?一个程?一台计机,一个商?一个银?或其他你想信ȝ东西.
Keytool应用实例:
1.产生一个keystore:
keytool -genkey -alias User(keystore的别? -keyalg RSA -validity 7 -keystore keystore(指定keystore).
q行q个命o,pȝ提示:
Enter keystore password:yourpassword(输入密码)
What is your first and last name?
[Unknown]: your name(输入你的名字)
What is the name of your organizational unit?
[Unknown]:your organizational(输入你所在组l单位的名字)
What is the name of your organization?
[Unknown]:your organization name (输入你所在组l的名字)
What is the name of your City or Locality?
[Unknown]:your city name(输入所在城市的名字)
What is the name of your State or Province?
[Unknown]:your provice name(输入所在省份名?
What is the two-letter country code for this unit?
[Unknown]:cn(输入国家名字)
Is CN=your name, OU=your organizaion, O="your organization name",
L=your city name, ST=your province name, C=cn correct?
[no]: yes
2.查一个keystore:
keytool -list -v -keystore keystore
Enter keystore password:your password(输入密码)
显Ckeystore內容?
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: yourname
Creation date: Dec 20, 2001
Entry type: keyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=yourname, OU=your organization, O="your organization name",
L=your city name, ST=your province name, C=CN
Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US
Serial number: 3c22adc1
Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
Certificate fingerprints:
MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
3.输出keystoreC个文?testkey:
keytool -export -alias duke -keystore keystore -rfc -file testkey
pȝ输出:
Enter keystore password:your password(输入密码)
Certificate stored in file < td>
4.输入证书C个新的truststore:
keytool -import -alias dukecert -file testkey -keystore truststore
Enter keystore password:your new password.(输入truststore新密?
5.查truststore:
keytool -list -v -keystore truststore
pȝ显Ctruststore的信?
现在可以用适当的keystoreq行你的应用E序.?
java -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password Server
? java -Djavax.net.ssl.trustStore=truststore
-Djavax.net.ssl.trustStorePassword=trustword Client
Q{Qby
2. 掌握多种语言。程序语aL有其最适合的领域。当你面寚w要解决的问题Ӟ你需要找C个最适合的语a来解册些问题。比如,如果你需要性能Q可能C/C++是首选,如果你需要跨q_Q可能Java是首选,如果你要写一个Web上的开发程序,那么PHPQASPQAjaxQJSP可能会是你的选择Q如果你要处理一些文本ƈ和别的应用交互,可能Perl, Python会是最好的。所以,׃些时间去探烦一下其它你q熟(zhn)的E序语言Q能让你的眼界变宽,因ؓ你被武装得更好,你思考问题也更为全面,q对于自己和目都会有好的帮助?/p>
3. 理性面对不同的操作pȝ或技?/strong>。程序员们L有自己心目中无可比拟的技术和操作pȝQ有的h喜欢UbuntuQ有的h喜欢DebianQ还有的人喜ƢWindowsQ以及FreeBSDQMacOSX或Solaris{等。看看我的BLOG(http://blog.csdn.net/haoel)中的那篇?a onclick="pageTracker._trackPageview('/outgoing/blog.csdn.net/haoel/archive/2007/03/19/1533720.aspx?referer=http%3A%2F%2Fwww.google.com%2Freader%2Fview%2F');" target="_blank">其实Unix很简?/a>》后的回复你q道程序员们在l护赯q忠爱时的那䆾执着了。只有一部分优秀的程序员明白不同操作pȝ的优势和长处和短处,q样Q在pȝ选型的时候,才能做到真正的客观和公正Q而不会让情A影响到自己。同P语言也是一P有太多的E序员L喜欢U缠于语a的对比,如:Java和Perl。哪个刚刚出道的E序员没有争论去cM的话题呢Q比如VC++和Delphi{等。争些东西只能表明自q肤浅和Q燥。优U的程序ƈ不会执着于这些,而是能够理性的分析和理心地面对Q从而才能客观地做出正确的选择?/p>
4. 别把自己框在单一的开发环境中?/strong> 再一ơ,正如上面所qͼ每个E序员都有自己忠q工具和技术,有的喜欢老的Q比如我喜ƢVi~辑E序Q,而有的喜Ƣ新的比如gedit或是Emacs{。有的喜Ƣ用像VC++一L(fng)囑Ş界面的调试器Q而我更喜ƢGDB命o行方面的调式器。等{等{。程序员在用什么样的工具上的争吗Q到处都是啊。用什么样的工h来无所谓,只要你能更好更快地达C的目的。但是有一Ҏ(gu)优秀E序员都应该了解的——那是应该d试一下别的工作环境。没有比较,你永q不知道谁好谁不好,你也永远不知道你所不知道的?/p>
5. 使用版本理工具理你的代码?/strong>千万不要告诉我你不知道源码的版本理Q如果你的团队开发的源代码ƈ没有版本理pȝQ那么我要告诉你Q你的Y件开发还处于矛_时代。赶快用一个版式本理工具吧。CVS 是一个看上去qxE无奇的版本工P但它是被使用最q的版本理pȝQSubversion 是CVS的一个升U版Q其正在开始接CVS的领地。Git 又是一个不同的版本理工具。还有Visual SourceSafe{。用什么样的版本管理工具依赖于你的团队的大和地理分布Q你也许正在使用最有效率或最没有效率的工h理你的源代码。但一个优U的程序员L会用一ƾ源码版本管理工h理自己的代码。如果你要我推荐一个,我推荐你使用开源的Subversion?/p>
6. 是一个优U的团队成员?/strong> 除非你喜Ƣ独奏,除非你是孤胆英雄。但我想告诉你,今天Q可能没有一个成熟的软g是你一个h能做的到的,你可能是你团队中最牛的大拿Q但qƈ不意味着你就是好的团队成员。你的能力只有放C个团队中才能施展开来。你在和你的团队成员交流中有CD吗?你是否经常和他们沟通,q且大家都喜Ƣ和你在一赯论问题?想一想一个球队吧,你是q个队中好的成员吗?当别人看C在场上的跑动Ӟ当别人看C的传球和接球和抢断时Q你的团员成员能因ؓ你的动作受到鼓舞吗? 7. 把你的工作变成文档?/strong> q一条目当然包括了在代码中写注释Q但那还仅仅不够Q你q需要做得更多。有良好的注释风格的代码是一个文档的基础Q他能够让你和你的团队容易的明白你的意图和想法。写下文档,q不仅仅是怕我们忘了当时的xQ而且q是一U团队的ȝ交流的方法,更是一U知识传递的Ҏ(gu)。记录下你所知道的一切会是一个好的习(fn)惯。因为,我相信你不希望别人L在你最忙的时候来打断你问问题Q或是你在休假的时候接到公司的?sh)话来询问你问题。而你自己如果老是守着自己的东西,其结果只可能是让你自己长旉地深陷在q块东西内,而你更本不可以d更多的事情。包括向上的晋升。你可能以ؓ“教会徒弟能饿d?#8221;Q但我告诉你Q你的保守会让你失去更多更好的东西,请你怿我,我绝不是在这里思h听闻?/p>
8. 注意备䆾和安全?/strong> 可能你觉得这是一?#8220;废话”Q你已明白了备䆾的重要性。但是,我还是要在这里提出,丢失东西是我们h生中的一部䆾Q你L会丢东西Q这点你永远无法避免。比如:你的W记本电(sh)脑被人偷了,你的盘损坏了,你的?sh)脑中病毒了Q你的系l被人入侵了Q甚x个大D烧了Q等{,{等。所以,做好备䆾工作是非帔R帔R要的事情Q硬盘是不可信的Q所以定期的d光盘或是带可能会是一个好的方法,|络也是不可信的Q所以小心病毒和黑客Q不但用Y件方面的安全{略Q你更需要一个健全的理制度。此外,量的让你的数据攑֜不同的地方,q做好定期(每日Q每周,每月Q的备䆾{略?/p>
9. 设计要够灵zR?/strong> 可能你的需求只会要求你实现一个死的东西,但是Q你作ؓ一个优U的程序,你应该随时在思考这个死的东西是否可以有灉|的一面,比如把一些参数变成可以配|的Q把一些公用的东西形成你的函数库以便以后重用,是否提供插g斚w的功能?你的模块是否要以像积木一样随意组合?如果要有修改的话Q你的设计是否能够马上应付?当然Q灵zȝ设计可能q不是要你去重新发明轮子Q你应该可能是使用标准化的东西。所谓灵话的设计是要让让考虑更多需求之外的东西Q把需求中q一cȝ问题都考虑刎ͼ而不是只处理需求中所说的那一特定的东ѝ比如说Q需要需要的屏幕分L率是800×600Q那么你的设计能否灵zM其他的分辨率Q程序设计L需要我们去处理不同的环境,以及未来的趋ѝ我们需要用动态的眼光L考问题,而不是刻舟求剑。也许有一天,你今天写的程序就要移植到别的环境中去Q那个时候你p真正明白什么是灉|的设计了?/p>
10. 不要搬v矛_砸自q脚?/strong>E序员L有一U不好的?fn)惯Q那是L惌快地完成自己手上的工作。但情况却往往事已愿违。越是想做得快,p是容易出问题Q越是想做得快,p是容易遗漏问题,最l,E序改过来改q去Q按下葫芦v了瓢Q最后花费的旉和精力反而更多。欲速而不达。优UE序员的?fn)惯是前面多׃些时间多作一些调查,试验一下不同的解决Ҏ(gu)Q如果时间允许,一个好的习(fn)惯是Q每4个小时的~程Q需要一个小时的休息Q然后又?个小时的~码。当Ӟq因异Q但其目的就是让你时常回头看看,让你想一惌样三个问题:1Q是否这么做是对的?2Q是否这么做考虑C所有的情况Q?Q是否有更好的方法?惛_了再_时常回头看看走过的\Q时常ȝ一下过MQ会对你有很大的帮助?/p>
]]>
症状Q服务器无法通过IP地址去访问,只能?27.0.0.1或者localhost来访问?/p>
解决办法Q?/p>
cmd q入dos 到bin?输入 run -b 192.168.50.39
启动JBOSS的时候输入:run -b xxx.xxx.xxx.xxx
其中xxx.xxx.xxx.xxx为本机的IP地址?/p>
原因Q?br style="line-height: normal" />
Ҏ(gu)2Q?br style="line-height: normal" />
修改 jboss-4.2.0.GA\server\default\deploy\jboss-web.deployer\server.xml ?Connector 下面?address Ҏ(gu)对应?IP 或?0.0.0.0 可以用 IP 讉K了?/span>
JBOSS版本Q?.2.2GA
症状Q服务器无法通过IP地址去访问,只能?27.0.0.1或者localhost来访问?br style="line-height: normal" />
解决办法Q?br style="line-height: normal" />
启动JBOSS的时候输入:run -b xxx.xxx.xxx.xxx
其中xxx.xxx.xxx.xxx为本机的IP地址?br style="line-height: normal" />
原因Q?br style="line-height: normal" />
JBOSS 4.2以上版本服务启动如果不加M参数的话,只监?27.0.0.1,是说只能用127.0.0.1或者localhost讉KQ用本机的对外地址讉K不了Q同一|络内别的机子没法访问。除非你用参?b ip地址 来绑定监听的地址才可以?br style="line-height: normal" />
q和以前版本的JBOSS不一P以前版本的不加Q何参数是监听本机所有的IP地址Q现在必M用参?b 0.0.0.0才可以监听全部地址?br style="line-height: normal" />
======================================
附,以下是我的具体解x法:
在jboss-4.2.2.GA\bin目录下,新徏start.bat文gQ录入如下内容:
run.bat -b 0.0.0.0
保存卛_。用你新制作的start.bat文g启动服务之后可以IP讉K了?br style="line-height: normal" />
2、概q?br />
1Q?什么是JMS
JMS是Java API, 允许应用E序来徏立、接收和d消息。程序依靠这些API, 在运行时需要一个JMS实现接口Q来提供理和控Ӟq被UCؓJMS provider, 现在有几U不同的JMS Provider; 在JBoss中的叫做JbossMQ?br />
2Q?JMS 和J2EE
JMS是在EJB和J2EE框架开发之前进行开发的Q所以在JMS说明书中没有涉及到EJB或J2EE?br />
EJB 和J2EEW一代版本中也没有涉及到JMSQ一直到EJB1.1Q在生成一个可用Beand的容器provider中JMS也不是必ȝAPI。在J2EE1.2中JMS接口是必需的情况,但ƈ不是非得要包含一个JMS ProviderQ在EJB2.0和J2EE1.3中又q行改变Q应用服务器包含了一个JMS ProviderQ自从J2EE1?需要EJB2.0Q增加了以下两个JMSҎ(gu):
w 一U新Beancd定义Q?也就是消息驱动Beam (MDB), q种bean做ؓJMS消息监听者,可以异步地处理JMS消息?br />
w JMS处理作ؓ资源Q来自一个Bean 的JMD 发布Q发送)必须能和其他bean的全局事务环境׃n。这个需要把JMS认ؓ是一个容器管理资源,象JDBC的连接?br />
3Q?JMS 和JBoss
JBoss?.0版本以后都支持JMS??.1中增加了MDBQ从2.4版本开始JMS作ؓ一个事务资源?br />
JBoss中JMS的体pȝ构如下:JMS Provider, 叫做JbossMQ ?是JBoss实现JMS 1.0.2规范的一部分Q包括可选部分,象ASFQApplication Service FacvilityQ?JbossMQ处理和普遍JMS一P建立 queues (队列)或topic(标题)Q持久性等?MDB (Message Driven Beans), 资源适配器?br />
3、JMS Provider
JBoss有它自己的JMS Provider 叫做JbossMQ?适合与JMS 1.0.2 的JMS ProviderQƈ且能用在所有^常的JMSE序中。ؓ了清楚在JBoss中JMS是如何工作的Q首先要清楚在JMS中涉及到的概念和术语Q最好的办法是阅读JMS规范Q下面给Z单的JMS介绍?br />
1) JMS的简单介l?br />
当你发送一个消息,你不能直接发送到Ҏ(gu)消息感兴的接受者。而是你发送到一个目的地。对此消息感兴趣的接受者必连接到目的圎ͼ得到此消息或在目的地讄订阅?br />
在JMS中有两种域:topics 和queues 。一个消息发送到一个topics Q可以有多个客户端。用topic发布允许一对多Q或多对多通讯通道。消息的产生者被叫做publisher, 消息接受者叫做subscriber?br />
queue 是另外一U方式,仅仅允许一个消息传送给一个客戗一个发送者将消息攑֜消息队列中,接受者从队列中抽取ƈ得到消息Q消息就会在队列中消失。第一个接受者抽取ƈ得到消息后,其他人就不能在得到它?br />
Z能发送和接收消息Q必dC个JMSq接。该q接是用JMS Provider得到q接的,在得到连接之后,建立一个会?Session)。然后再建立publisher/sender 来发送消息或subscriber/receiver来接收消息?br />
q行Ӟ如果使用topic 那么publisher 或subscriber 通过一个topic来关联,如果使用queue Q则sender 或receiver通过queue来关联v来?br />
通常Q在JMS框架中运转的Ҏ(gu)如下Q?br />
(1) 得到一个JNDI初始化上下文(Context)Q?br />
(2) Ҏ(gu)上下文来查找一个连接工厂TopicConnectFactory/ QueueConnectionFactory (有两U连接工厂,Ҏ(gu)是topic/queue来用相应的cd)Q?br />
(3) 从连接工厂得C个连?Connect 有两U[TopicConnection/ QueueConnection]);
(4) 通过q接来徏立一个会?Session);
(5) 查找目的?Topic/ Queue);
(6) Ҏ(gu)会话以及目的地来建立消息刉?TopicPublisher/QueueSender)和消费?TopicSubscriber/ QueueReceiver).
Z得到一个连接和得到一个目的地Q用来关联publisher/sender 或subscriber/receiverQ,必须用provider-specific参数?br />
通过JNDI来查扄应的q接工厂或目的地QJNDI适合于Q何JMS Provider。但是查扄的名字是provider使用的。因此,在你使用的JMS ProviderQ其中包括JBossMQQ,必须学会如何q行指定。JMS Provider中的M讄Q象q接Ҏ(gu),用到目的地等Q在用到的Provider都有明确描述?br />
2) 配置
当用一个JMS ProviderӞ有三个Provider-specific因素Q?br />
w 得到一个JNDI初始化上下文
w 用到的连接工厂的名字?br />
w 对目的地的管理和命名协定?br />
JBoss同它的JNDI一h行。ؓ了简单的JMS clientQ?配置和查扑ֈ始化上下文,同实现其他J2EE客户端一栗?br />
JMS-specific 来约束JBoss 的JMS provider (JBossMQ)。JbossMQ是通过xml 文gjbossmq-service.xmlq行配置的,该文件放在在server\default\deploy下?br />
在xml文g中最基本的三件事情:
w 增加一个新的目的地
w 配置用户
w 获得可用q接工厂的名字?br />
(1) 增加新的目的?br />
w 在目的地的xml文g在jboss 3.x中是jbossmq-destinations-service.xmlQserver/../deployQ。在文g中已l存在几个缺省的目的圎ͼ所以你比较Ҏ(gu)明白怎样增加到文件中。在例子中你需要一个topic目的?spoolQ所以增加下面的语句到jbossmq-destinations-service.xml中。这U方式是长久存在的,不随着JBoss服务器关闭而消失?br />
<mbean code="org.jboss.mq.server.jmx.Topic"
name="jboss.mq.destination:service=Topic,name=spool">
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
w 另外一U方法是可以通过JMX HTML理界面。通过http://localhost:8080/jmx-console 来访问。在jboss.mq 下查找service=DestinationManager 的连接。然后在createTopic()或createQueue()来徏立,q种Ҏ(gu)建立的目的地是(f)时性的Q随着服务器开始存在,当当JBoss 服务器重新启动时Q动态徏立的目的地将会不存在。在JbossMQ中所有目的地都有一个目的地cd的前~。对于topic前缀是topic ,对于queues前缀是queue。例如查找一个testTopic目的圎ͼ需要查扑字ؓ“topic/testTopic”?br />
在此U方法中有createTopic()或createQueue()分别有两U方法:一是有两个参数Q二是有一个参数的。两个参数分别是Q徏立的目的地名U和JNDI名称。一个参数的只是目的地名Uͼ对于JNDI名称默认是:[目的地类?topic/queue) ]/目的地名U?br />
在这里我们用的是第一U方法。直接修改jbossmq-destinations-service.xml文g?br />
(2) 理用户
在JMS中可能关联一个连接和一个用P不幸的是没有明确的方法来限制讉KJbossMQ或访问特D的目的地到一个给定的用户。ؓ了给大部分角Ԍ在JbossMQ中不需要徏立用P除非x一个持久topic订阅者。在q个例子中,用户是必ȝ?br />
用户可以直接在文件jbossmq-state.xmlQserver/../confQ中d。同样也可以使用JMX HTML理界面来增加(jboss.mq->service=StateManager->addUser()Q?br />
<User>
<Name>jacky</Name>
<Password>jacky</Password>
<Id>DurableSubscriberExample</Id>
</User>>
(3) q接工厂
JBossMQ 包括为topic和queue几个不同的连接工厂,每个q接工厂有自q性。当通过JNDI来查找一个连接工厂时Q需要知道此q接工厂的名U。所有可用连接工厂和它们的属性,名称都会在文件jbossmq-service.xml中?br />
有三U类型连接工厂,依赖的通讯协议如下Q?br />
OIL
快速双向scoket通讯协议。它是缺省的?br />
UIL
过一个socket协议Q可以用在通过防火墙访问,或者当客户端不能正的查找到服务器的IP地址?br />
RMI
最早的协议Q是E_的,但是比较慢?br />
JVM
在JBoss 2.4之后增加的一个新的连接工厂类型。不需要用socketQ当客户端和JbossMQ使用同样虚拟机时Q可以用?br />
在JBoss2.4.1以后版本中,对于topic- ?queue-目的圎ͼq接工厂使用同样的名字。下表列Z在JBoss中JMSq接工厂Q?br />
目的地类?JNDI名字 q接工厂cd
Topic/Queue java:/ConnectionFactory JVM
Topic/Queue java:/XAConnectionFactory JVM支持XA事务
Topic/Queue RMIConnectionFactory RMI
Topic/Queue RMIXAConnectionFactory RMI支持XA事务
Topic/Queue ConnectionFactory OIL
Topic/Queue XAConnectionFactory OIL支持XA事务
Topic/Queue UILConnectionFactory UIL
Topic/Queue UILXAConnectionFactory UIL支持XA事务
3Q?JBoss中高UJMS配置
在上Ҏ(gu)落主要描qC和JbossMQ一起实行的基本配置工作。在本段来描qJMS其他配置?br />
(1) JMS持久性管?br />
JMS持久性管?PM)负责存储消息Qƈ且将消息标记为持久,如果服务器发生故障时Q能保证消息不会丢失Qƈ允许恢复持久性消息。持久性JMS消息可以使用不同的方法来完成。每个方法有自己优点和缺P
PM 名字 优点 ~点
File 比较E_ 速度?br />
Rollinglogged 速度比较?此方法比较新Q有些地斚w要完?br />
JDBC 对于E_性和可量性比较好 必须有JDBC
Logged 速度?Log files grow without bound, memory management problems during recovery
在JBoss中缺省的持久性消息管理是File持久性管理。可以改变它Q但必须对于一个JMS
Server有且仅有一个持久性管理配|。所以你在JBoss理界面的jboss.mq – >
service=PersistenceManager 只是看到一个?br />
持久性管理的配置文g是jbossmq-service.xml。在server\..\deploy下?br />
Z让大家了解持久性管理的各种Ҏ(gu)Q我下面来逐个介绍如何配置?br />
w File持久性管?br />
File持久性管理的概念是为每一个持久性消息徏立一个文件。消息持久性方法不是全部都能用,但它是比较稳定的?br />
File持久性管理在JBoss发布Ӟ作ؓ一个缺省的持久性管理。如果你打开jbossmq-service.xml文gQ你会看C面的XMLQ?br />
<mbean code="org.jboss.mq.pm.file.PersistenceManager"
name="jboss.mq:service=PersistenceManager">
<attribute >db/jbossmq/file</attribute>
<depends optional-attribute-name="MessageCache">jboss.mq:service=MessageCache</depends>
</mbean>
当设|Mbean配置ӞFile持久性管理允怽指定下面的属性:
DataDircetory 是存放持久性消息的路径Q会把生成的数据文g攑֜此目录下?/p>
w 讄Rollinglogged持久性管?br />
Rollinglogged持久性管理是比较新的一U持久性消息管理方法,因ؓ它用日志文件来持箋多个消息Q所以当建立一个文件时Q不需要许多的I/O?br />
定义Rollinglogged持久性管理:
<mbean code="org.jboss.mq.pm.rollinglogged.PersistenceManager"
name="jboss.mq:service=PersistenceManager">
<attribute >db/jbossmq/file</attribute>
<depends optional-attribute-name="MessageCache">jboss.mq:service=MessageCache</depends>
</mbean>
Rollinglogged持久性管理中DataDirctory 存放持久性消息的路径Q会把生成的数据文g攑֜此目录下?/p>
w 讄JDBC持久性管?br />
JDBC持久性管理用数据库表来存储消息。需要一个JBoss配置的数据源来访问数据库。具体内容参考jbossmq-service.xml文g中的内容?br />
w 讄Logged持久性管?br />
Logged持久性管理是比较早的一个,在JBoss2.4.1以后版本中不在徏议用。现在有其他更好的办法?br />
4、D例说?br />
当我们清楚了以后内容后,现在我们来用JBoss实现一个例子来加深对JBoss和JMS的了解?br />
在上面叙qCQ我们知道明用JMS provider有三个基本的事情要做Q配|JNDI初始化上下文Q连接工厂的名字和用目的地的名字?br />
当编写品的最好的事情是不受provider-specific 影响Q代码能在不同的JMS provider之间Ҏ(gu)UL。在此这个例子没有聚焦在开发品上Q而是解释如何使用JbossMQ来工作?br />
1) 初始化上下文
w 配置JNDI的一个方法是通过属性文件jndi.properties。在q个文g中用正的|q且把它所在的路径包含到classpath中,它比较容获得正确初始化上下文?br />
jndi.properties文g的内容如下:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
把该文g攄的\径成Z的classpath的一部分。如果你使用q种Ҏ(gu)Q在初始化上下文Ӟ代码比较? Context context = new IntialContext();1
w 在某些情景下Q可能需要手工配|JNDIQ例如当q行的类文g中环境已l配|了一个初始化上下文,但不是你想用的上下文Ӟ需要手工来配置一个上下文。设|在哈希表中的几个属性|q且使用此哈希表来实例化一个上下文。定义语法:
Hashtable props = new Hashtable();
props.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
props.put(Context.PROVIDER_URL, "localhost:1099");
props.put("java.naming.rmi.security.manager", "yes");
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming");
2) 查找q接工厂
自有了上下文后,需要查找一个连接工厂。ؓ了查扑֮Q用一个可用的名字。查找连接工厂的代码如下Q?br />
对于一个topic目的?br />
TopicConnectionFactory topicFactory = (TopicConnectionFactory) context.lookup (“ConnectionFactory”)
Queue 目的圎ͼ
QueueConnectionFactory queueFactory = (QueueConnectionFactory ) context.lookup (“ConnectionFactory”)
3) 建立q接和会?br />
在我们有了连接工厂后Q徏立一个连接,在此q接中徏立一个会话?br />
对于topic代码如下Q?br />
//建立一个连?br />
topicConnection = topicFactory.createTopicConnection();
//建立一个会?br />
topicSession = topicConnection.createTopicSession(false, //不需要事?br />
Session.AUTO_ACKNOLEDGE //自动接收消息的收条?br />
);
对于queue代码如下Q?br />
//建立一个连?br />
queueConnection = queueFactory.createQueueConnection();
//建立一个会?br />
queueSession = queueConnection .createQueueSession(false, //不需要事?br />
Session.AUTO_ACKNOLEDGE //自动接收消息的收条?br />
);
一个会话徏立时Q配|是否调用事?br />
在事务Session中,当事务被提交后,自动接收Q如果事务回滚,所有的被消费的消息会被重新发送?br />
在非事务Session中,如果没有调用事务处理Q消息传递的方式有三U:
Session.AUTO_ACKNOWLEDGE :当客h调用的receiveҎ(gu)成功q回Q或当MessageListenser 成功处理了消息,session会自动接收消息的收条?br />
Session.CLIENT_ACKNOWLEDGE Q客h通过调用消息的acknowledgeҎ(gu)来接收消息。接收发生在session层。接收到一个被消费的消息时Q将自动接收该session已经消费的所有消息。例如:如果消息的消费者消费了10条消息,然后接收15个被传递的消息Q则前面?0个消息的收据都会在这15个消息中被接收?br />
Session.DUPS_ACKNOWLEDGE Q指Csession~慢接收消息?/p>
4) 查找目的?br /> 现在我们来介l徏立publishes/sends 或subscribles/receives消息?br /> 下面的代码列出来查找一个目的地Q?br /> 对于topic 查找一个testTopic目的?br /> Topic topic = (Topic) context.lookup(“topic/testTopic”);
对于queue 查找一个testQueue目的?br />
Queue queue= (Queue) context.lookup(“queue/testQueue”);
注意QJbossM的前~topic/ (queue/)通常被放在topic (queue)名字前面?br />
在JMS中,当客h扮演每种角色Q象对于topic来将的publisher ,subscriber 或对于queue来将的sender, receiverQ?都有自己不同cȝ承和不同函数?br />
5) 建立一个消息制造者Message Producer (topic publisher/ queue sender)
消息刉者是一个由session创徏的对象,主要工作是发送消息到目的地?br />
对于一个topicQ需要通过TopicSession来创Z个TopicPublisher。代码如下:
TopicPublisher topicPublisher = TopicSession.createPublisher(topic);
对于一个queueQ需要通过QueueSession来创Z个QueueSender。代码如下:
QueuePublisher queuePublisher = queueSession.createSender(queue);
6) 消息发?br />
建立一个TestMessageq且publish 它, 代码Q?br />
TextMessage message = topicSession.createTestMessage();
message.setText(msg);
topicPublishe.publish(topic, message);
建立一个TestMessageq且send它, 代码Q?br />
TextMessage message = queueSession.createTestMessage();
message.setText(msg);
queueSender.send(queue, message);
7) 下面是一个完成的topic publisher 代码Q文件名HelloPublisher.java Q?br />
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.TopicSession;
import javax.jms.TopicPublisher;
import javax.jms.Topic;
import javax.jms.TextMessage;
import javax.jms.Session;
import javax.jms.JMSException;
import java.util.Hashtable;
public class HelloPublisher {
TopicConnection topicConnection;
TopicSession topicSession;
TopicPublisher topicPublisher;
Topic topic;
public HelloPublisher(String factoryJNDI, String topicJNDI)
throws JMSException, NamingException {
Hashtable props=new Hashtable();
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
props.put(Context.PROVIDER_URL, "localhost:1099");
props.put("java.naming.rmi.security.manager", "yes");
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming");
Context context = new InitialContext(props);
TopicConnectionFactory topicFactory =
(TopicConnectionFactory)context.lookup(factoryJNDI);
topicConnection = topicFactory.createTopicConnection();
topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
topic = (Topic)context.lookup(topicJNDI);
topicPublisher = topicSession.createPublisher(topic);
}
public void publish(String msg) throws JMSException {
TextMessage message = topicSession.createTextMessage();
message.setText(msg);
topicPublisher.publish(topic, message);
}
public void close() throws JMSException {
topicSession.close();
topicConnection.close();
}
public static void main(String[] args) {
try {
HelloPublisher publisher = new HelloPublisher(
"ConnectionFactory", "topic/testTopic");
for (int i = 1; i < 11; i++) {
String msg = "Hello World no. " + i;
System.out.println("Publishing message: " + msg);
publisher.publish(msg);
}
publisher.close();
} catch(Exception ex) {
System.err.println(
"An exception occurred while testing HelloPublisher25: " + ex);
ex.printStackTrace();
}
}
}
我们知道Q用JMS不仅能发送(sendQ?发布QpublishQ消息,也能获得QsendQ?发布QpublishQ的消息。在旉方式有良U方法来做:
w 同步QSynchronouslyQ:需要手工的d到消息,Z得到一个消息客h调用Ҏ(gu)得到消息Q直到消息到达或在规定的旉内没有到达而超时。我们在例子中没有说明这部分Q大家可以实验一下?br />
w 异步QAsynchronouslyQ:你需要定义一个消息监听器(MessageListener),实现该接口。当消息辑ֈӞJMS provider通过调用该对象的 onMessageҎ(gu)来传递消息?br />
从原则来,topic和queue都是异步的,但是在这两种目的C有不同的cdҎ(gu)。首先,必须定义一个MessageListener接口?
8) 建立一个MessageListener
在徏立了你需要的subscriber/receiverQƈ且登C监听器后。就可以调用q接的startҎ(gu)得到JMS provider 发送到的消息了。如果在登记监听器之前调用startҎ(gu)Q很可能会丢失消息?br />
public void onMessage(Message m) {
try {
String msg = ((TextMessage)m).getText();
System.out.println("HelloSubscriber got message: " + msg);
} catch(JMSException ex) {
System.err.println("Could not get text message: " + ex);
ex.printStackTrace();
}
}
9) 建立消息消费?br />
对于topic来将Q?br />
//建立一个订阅?br />
topicSubscriber = topicSession.createSubscriber(topic);
//讄消息监听器,
topicSubscriber.setMessageListener(this)
//q接开?br />
topicConnection.start();
对于queue来将Q?br />
//建立一个订阅?br />
queueReceiver = queueSession.createReceiver(queue);
//讄消息监听器,
queueReceiver .setMessageListener(this)
//q接开?br />
queueConnection.start();
10) 完整的代码,攑֜文gHelloSubscriber.java中,如下Q?br />
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.jms.Topic;
import javax.jms.Message;
import javax.jms.TextMessage;
import javax.jms.Session;
import javax.jms.MessageListener;
import javax.jms.JMSException;
public class HelloSubscriber implements MessageListener {
TopicConnection topicConnection;
TopicSession topicSession;
TopicSubscriber topicSubscriber;
Topic topic;
public HelloSubscriber(String factoryJNDI, String topicJNDI)
throws JMSException, NamingException
{
Context context = new InitialContext();
TopicConnectionFactory topicFactory =
(TopicConnectionFactory)context.lookup(factoryJNDI);
topicConnection = topicFactory.createTopicConnection();
topicSession = topicConnection.createTopicSession(
false, Session.AUTO_ACKNOWLEDGE);
topic = (Topic)context.lookup(topicJNDI);
topicSubscriber = topicSession.createSubscriber(topic);
topicSubscriber.setMessageListener(this);
System.out.println(
"HelloSubscriber subscribed to topic: " + topicJNDI);
topicConnection.start();
}
public void onMessage(Message m) {
try {
String msg = ((TextMessage)m).getText();
System.out.println("HelloSubscriber got message: " + msg);
} catch(JMSException ex) {
System.err.println("Could not get text message: " + ex);
ex.printStackTrace();
}
}
public void close() throws JMSException {
topicSession.close();
topicConnection.close();
}
public static void main(String[] args) {
try {
HelloSubscriber subscriber = new HelloSubscriber(
"TopicConnectionFactory",
"topic/testTopic");
} catch(Exception ex) {
System.err.println(
"An exception occurred while testing HelloSubscriber: " + ex);
ex.printStackTrace();
}
}
}
11) ~辑、运行程?br />
直接使用命oQjavaQ?
w 开启命令操作符。设|classpath :
set classpath=C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jboss-j2ee.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jnp-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\log4j.jar;.
w 首先q行订阅消息端:java HelloSubscriber
w 再开启另外一个命令窗口设|classpath :
set classpath=C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jboss-j2ee.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jnp-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\log4j.jar;.
w q行发布消息端:java HelloPublisher
5、补?br />
在最后我们解释JBoss-specificҎ(gu):如何用代码来理目的地。JBoss各个版本可能不同Q但是差别不大。我使用的是jboss3.0.6?br />
实现q个目的有两U不同的Ҏ(gu)Q依赖于是否代码是在和JBoss同样的虚拟机q是独立独立的。它们都包括调用一个通过service=DestinationManager 登记的JMX Bean。这个Mbean 有四个方法来理目的圎ͼcreateTopic()QcreateQueue()QdestroyTopic()QdestroyQueue()?br />
在代码中实现理目的地在影射怎样调用MBean有不同的地方。如果程序虚拟机和Mbean服务器一P可以直接调用?br />
建立一个topic 目的地的代码如下Q?br />
MBeanServer server = (MBeanServer)
MBeanServerFactory.findMBeanServer(null).iterator().next();
server.invoke(new ObjectName("JBossMQ", "service", "DestinationManager"),
method,
new Object[] { “myTopic” },
new String[] { "java.lang.String" });
如果E序和Mbean服务器的虚拟Z同,需要通过一个JMX adapter。一个JMX adapter是一个HTML GUI。用E序通过URL来调用Mbean。代码如下:
import java.io.InputStream;
import java.net.URL;
import java.net.HttpURLConnection;
import javax.management.MBeanServerFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.jms.Topic;
import javax.jms.Queue;
public class DestinationHelper {
static final String HOST = "localhost";
static final int PORT = 8080;
static final String BASE_URL_ARG = "/jmx-console/HtmlAdaptor?";
public static void createDestination(Class type, String name)
throws Exception
{
String method = null;
if (type == Topic.class) { method = "createTopic"; }
else if (type == Queue.class) { method = "createQueue";}
invoke(method, name);
}
public static void destroyDestination(Class type, String name)
throws Exception
{
String method = null;
if (type == Topic.class) { method = "destroyTopic"; }
else if (type == Queue.class) { method = "destroyQueue";}
invoke(method, name);
}
protected static void invoke(String method, String destName)
throws Exception
{
try {
MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).iterator().next();
invokeViaMBean(method, destName);
}catch(Exception ex) { invokeViaUrl(method, destName);}
}
protected static void invokeViaUrl(String method, String destName)
throws Exception
{
String action = "action=invokeOp&methodIndex=6&name=jboss.mq%3Aservice%3DDestinationManager&arg0=" + destName;
String arg = BASE_URL_ARG + action;
URL url = new URL("http", HOST, PORT, arg);
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.connect();
InputStream is = con.getInputStream();
java.io.ByteArrayOutputStream os = new java.io.ByteArrayOutputStream();
byte[] buff = new byte[1024];
for(;;) {
int size = is.read( buff );
if (size == -1 ) { break; }
os.write(buff, 0, size);
}
os.flush();
if (con.getResponseCode() != HttpURLConnection.HTTP_OK ) {
throw new Exception ("Could not invoke url: " + con.getResponseMessage() );
} else {
System.out.println("Invoked URL: " + method + " for destination " + destName + "got resonse: " + os.toString());
}
}
protected static void invokeViaMBean(String method, String destName)
throws Exception
{
MBeanServer server = (MBeanServer)MBeanServerFactory.findMBeanServer(null).iterator().next();
server.invoke(new ObjectName("JBossMQ", "service", "DestinationManager"),
method,
new Object[] { destName },
new String[] { "java.lang.String" });
}
public static void main(String[] args) {
try {
if (args.length >0){
destroyDestination(Topic.class,"myCreated");
}else {
createDestination(Topic.class,"myCreated");
}
}catch(Exception ex) {
System.out.println("Error in administering destination: " + ex);
ex.printStackTrace();
}
}
}
~辑命oQ?br />
javac -classpath C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\lib\jboss-jmx.jar;. DestinationHelper.java
q行命o
java -classpath C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\lib\jboss-jmx.jar;. DestinationHelper
当运行完后查?a href="http://localhost:8080/jmx-console">http://localhost:8080/jmx-console下面的jboss.mq.destination中有name=myCreated,service=Topic
表明你徏立成功。当JBoss关闭重新启动时。该目的C会在存在?/p>
BlockingQueue 不接?null 元素。试?add、put ?offer 一?null 元素Ӟ某些实现会抛?NullPointerException。null 被用作指C?poll 操作p|的警戒倹{?/p>
BlockingQueue 可以是限定容量的。它在Q意给定时间都可以有一?remainingCapacityQ超出此定wQ便无法无阻塞地 put 额外的元素?br /> 没有M内部定wU束?BlockingQueue L报告 Integer.MAX_VALUE 的剩余容量?/p>
BlockingQueue 实现主要用于生?使用者队列,但它另外q支?Collection 接口。因此,举例来说Q?remove(x) 从队列中U除L一个元素是有可能的?br /> 然而,q种操作通常?会有效执行,只能有计划地偶尔使用Q比如在取消排队信息时?/p>
BlockingQueue 实现是线E安全的。所有排队方法都可以使用内部锁定或其他Ş式的q发控制来自动达到它们的目的?br /> 然而,大量?Collection 操作QaddAll、containsAll、retainAll ?removeAllQ没?必要自动执行Q除非在实现中特别说明?br /> 因此QD例来_在只d?c 中的一些元素后QaddAll(c) 有可能失败(抛出一个异常)?/p>
BlockingQueue 实质上不 支持使用M一U?#8220;close”?#8220;shutdown”操作来指CZ再添加Q何项?br /> q种功能的需求和使用有依赖于实现的們。例如,一U常用的{略是:对于生者,插入Ҏ(gu)?end-of-stream ?poison 对象QƈҎ(gu)使用者获取这些对象的旉来对它们q行解释?/p>
下面的例子演CZq个d队列的基本功能?/p>
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class MyBlockingQueue extends Thread {
public static BlockingQueue<String> queue = new LinkedBlockingQueue<String>(3);
private int index;
public MyBlockingQueue(int i) {
this.index = i;
}
public void run() {
try {
queue.put(String.valueOf(this.index));
System.out.println("{" + this.index + "} in queue!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
service.submit(new MyBlockingQueue(i));
}
Thread thread = new Thread() {
public void run() {
try {
while (true) {
Thread.sleep((int) (Math.random() * 1000));
if(MyBlockingQueue.queue.isEmpty())
break;
String str = MyBlockingQueue.queue.take();
System.out.println(str + " has take!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.submit(thread);
service.shutdown();
}
}
---------------------执行l果-----------------
{0} in queue!
{1} in queue!
{2} in queue!
{3} in queue!
0 has take!
{4} in queue!
1 has take!
{6} in queue!
2 has take!
{7} in queue!
3 has take!
{8} in queue!
4 has take!
{5} in queue!
6 has take!
{9} in queue!
7 has take!
8 has take!
5 has take!
9 has take!
-----------------------------------------
CompletionService
生产新的异步Q务与使用已完成Q务的l果分离开来的服务。生产?submit 执行的Q务。用?take 已完成的dQ?br /> q按照完成这些Q务的序处理它们的结果。例如,CompletionService 可以用来理异步 IO Q执行读操作的Q务作为程序或pȝ的一部分提交Q?br /> 然后Q当完成L作时Q会在程序的不同部分执行其他操作Q执行操作的序可能与所h的顺序不同?/p>
通常QCompletionService 依赖于一个单独的 Executor 来实际执行Q务,在这U情况下Q?br /> CompletionService 只管理一个内部完成队列。ExecutorCompletionService cL供了此方法的一个实现?/p>
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyCompletionService implements Callable<String> {
private int id;
public MyCompletionService(int i){
this.id=i;
}
public static void main(String[] args) throws Exception{
ExecutorService service=Executors.newCachedThreadPool();
CompletionService<String> completion=new ExecutorCompletionService<String>(service);
for(int i=0;i<10;i++){
completion.submit(new MyCompletionService(i));
}
for(int i=0;i<10;i++){
System.out.println(completion.take().get());
}
service.shutdown();
}
public String call() throws Exception {
Integer time=(int)(Math.random()*1000);
try{
System.out.println(this.id+" start");
Thread.sleep(time);
System.out.println(this.id+" end");
}
catch(Exception e){
e.printStackTrace();
}
return this.id+":"+time;
}
}
CountDownLatch
一个同步辅助类Q在完成一l正在其他线E中执行的操作之前,它允怸个或多个U程一直等待?/p>
用给定的计数 初始?CountDownLatch。由于调用了 countDown() Ҏ(gu)Q所以在当前计数到达零之前,await Ҏ(gu)会一直受d?br /> 之后Q会释放所有等待的U程Qawait 的所有后l调用都立卌回。这U现象只出现一ơ——计数无法被重置。如果需要重|计敎ͼ误虑使用 CyclicBarrier?/p>
CountDownLatch 是一个通用同步工具Q它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器Q?br /> 或入口:在通过调用 countDown() 的线E打开入口前,所有调?await 的线E都一直在入口处等待?br /> ?N 初始化的 CountDownLatch 可以使一个线E在 N 个线E完成某Ҏ(gu)作之前一直等待,或者其在某项操作完成 N ơ之前一直等待?/p>
CountDownLatch 的一个有用特性是Q它不要求调?countDown Ҏ(gu)的线E等到计数到N时才l箋Q?br />
而在所有线E都能通过之前Q它只是LMU程l箋通过一?await?
一下的例子是别人写的,非常形象?/p>
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCountDownLatch {
public static void main(String[] args) throws InterruptedException {
// 开始的倒数?br />
final CountDownLatch begin = new CountDownLatch(1);
// l束的倒数?br />
final CountDownLatch end = new CountDownLatch(10);
// 十名选手
final ExecutorService exec = Executors.newFixedThreadPool(10);
for (int index = 0; index < 10; index++) {
final int NO = index + 1;
Runnable run = new Runnable() {
public void run() {
try {
begin.await();//一直阻?br />
Thread.sleep((long) (Math.random() * 10000));
System.out.println("No." + NO + " arrived");
} catch (InterruptedException e) {
} finally {
end.countDown();
}
}
};
exec.submit(run);
}
System.out.println("Game Start");
begin.countDown();
end.await();
System.out.println("Game Over");
exec.shutdown();
}
}
CountDownLatch最重要的方法是countDown()和await()Q前者主要是倒数一ơ,后者是{待倒数?Q如果没有到?Q就只有d{待了?/p>
CyclicBarrier
一个同步辅助类Q它允许一l线E互相等待,直到到达某个公共屏障?(common barrier point)?br /> 在涉及一l固定大的U程的程序中Q这些线E必M时地互相{待Q此?CyclicBarrier 很有用。因 barrier 在释攄待线E后可以重用Q所以称它ؓ循环 ?barrier?/p>
CyclicBarrier 支持一个可选的 Runnable 命oQ在一l线E中的最后一个线E到达之后(但在释放所有线E之前)Q?br /> 该命令只在每个屏障点q行一ơ。若在l所有参与线E之前更新共享状态,此屏障操?很有用?/p>
CZ用法Q下面是一个在q行分解设计中?barrier 的例子,很经典的旅行团例子:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCyclicBarrier {
// 徒步需要的旉: Shenzhen, Guangzhou, Shaoguan, Changsha, Wuhan
private static int[] timeWalk = { 5, 8, 15, 15, 10 };
// 自驾?br />
private static int[] timeSelf = { 1, 3, 4, 4, 5 };
// 旅游大巴
private static int[] timeBus = { 2, 4, 6, 6, 7 };
static String now() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date()) + ": ";
}
static class Tour implements Runnable {
private int[] times;
private CyclicBarrier barrier;
private String tourName;
public Tour(CyclicBarrier barrier, String tourName, int[] times) {
this.times = times;
this.tourName = tourName;
this.barrier = barrier;
}
public void run() {
try {
Thread.sleep(times[0] * 1000);
System.out.println(now() + tourName + " Reached Shenzhen");
barrier.await();
Thread.sleep(times[1] * 1000);
System.out.println(now() + tourName + " Reached Guangzhou");
barrier.await();
Thread.sleep(times[2] * 1000);
System.out.println(now() + tourName + " Reached Shaoguan");
barrier.await();
Thread.sleep(times[3] * 1000);
System.out.println(now() + tourName + " Reached Changsha");
barrier.await();
Thread.sleep(times[4] * 1000);
System.out.println(now() + tourName + " Reached Wuhan");
barrier.await();
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
}
}
public static void main(String[] args) {
// 三个旅行?br />
CyclicBarrier barrier = new CyclicBarrier(3);
ExecutorService exec = Executors.newFixedThreadPool(3);
exec.submit(new Tour(barrier, "WalkTour", timeWalk));
exec.submit(new Tour(barrier, "SelfTour", timeSelf));
//当我们把下面的这D代码注释后Q会发现Q程序阻塞了Q无法l运行下厅R?br />
exec.submit(new Tour(barrier, "BusTour", timeBus));
exec.shutdown();
}
}
CyclicBarrier最重要的属性就是参与者个敎ͼ另外最要方法是await()。当所有线E都调用了await()后,pC些线E都可以l箋执行Q否则就会等待?/p>
Future
Future 表示异步计算的结果。它提供了检查计是否完成的Ҏ(gu)Q以{待计算的完成,q检索计的l果?br /> 计算完成后只能?get Ҏ(gu)来检索结果,如有必要Q计完成前可以d此方法。取消则?cancel Ҏ(gu)来执行?br /> q提供了其他Ҏ(gu)Q以定d是正常完成还是被取消了。一旦计完成,׃能再取消计算?br /> 如果Z可取消性而?Future但又不提供可用的l果Q则可以声明 Future<?> 形式cd、ƈq回 null 作ؓ基础d的结果?/p>
q个我们在前面CompletionService已经看到了,q个Future的功能,而且q个可以在提交线E的时候被指定Z个返回对象的?/p>
ScheduledExecutorService
一?ExecutorServiceQ可安排在给定的延迟后运行或定期执行的命令?/p>
schedule Ҏ(gu)使用各种延迟创徏dQƈq回一个可用于取消或检查执行的d对象。scheduleAtFixedRate ?scheduleWithFixedDelay Ҏ(gu)创徏q执行某些在取消前一直定期运行的d?/p>
?Executor.execute(java.lang.Runnable) ?ExecutorService ?submit Ҏ(gu)所提交的命令,通过所h?0 延迟q行安排?br /> schedule Ҏ(gu)中允许出?0 和负数gq(但不是周期)Qƈ这些视ZU立x行的h?/p>
所有的 schedule Ҏ(gu)都接受相?延迟和周期作为参敎ͼ而不是绝对的旉或日期。将?Date 所表示的绝Ҏ(gu)间{换成要求的Ş式很Ҏ(gu)?br /> 例如Q要安排在某个以后的日期q行Q可以用:schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)?br /> 但是要注意,׃|络旉同步协议、时钟漂UL其他因素的存在,因此相对延迟的期满日期不必与启用d的当?Date 相符?br /> Executors cMؓ此包中所提供?ScheduledExecutorService 实现提供了便L(fng)工厂Ҏ(gu)?/p>
一下的例子也是|上比较行的?/p>
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
public class TestScheduledThread {
public static void main(String[] args) {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
final Runnable beeper = new Runnable() {
int count = 0;
public void run() {
System.out.println(new Date() + " beep " + (++count));
}
};
// 1U钟后运行,q每?U运行一?br />
final ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate(beeper, 1, 2, SECONDS);
// 2U钟后运行,q每ơ在上次dq行完后{待5U后重新q行
final ScheduledFuture beeperHandle2 = scheduler.scheduleWithFixedDelay(beeper, 2, 5, SECONDS);
// 30U后l束关闭dQƈ且关闭Scheduler
scheduler.schedule(new Runnable() {
public void run() {
beeperHandle.cancel(true);
beeperHandle2.cancel(true);
scheduler.shutdown();
}
}, 30, SECONDS);
}
}
q样我们把concurrent包下比较重要的功能都已经ȝ完了Q希望对我们理解能有帮助?/p>
接下来逐一介绍
Executors主要Ҏ(gu)说明 newCachedThreadPoolQ无界线E池Q可以进行自动线E回Ӟ newSingleThreadExecutorQ单个后台线E) q些Ҏ(gu)q回的都是ExecutorService对象Q这个对象可以理解ؓ是一个线E池?br />
q个U程池的功能q是比较完善的。可以提交Q务submit()可以l束U程池shutdown()?/p>
import java.util.concurrent.ExecutorService; public class MyExecutor extends Thread { 虽然打印了一些信息,但是看的不是非常清晰Q这个线E池是如何工作的Q我们来休眠的旉调长10倍?br />
Thread.sleep((int)(Math.random()*10000)); 再来看,会清楚看到只能执?个线E。当执行完一个线E后Q才会又执行一个新的线E,也就是说Q我们将所有的U程提交后,U程池会{待执行完最后shutdown。我们也会发玎ͼ提交的线E被攑ֈ一?#8220;无界队列?#8221;。这是一个有序队列(BlockingQueueQ这个下面会说到Q?/p>
另外它用了Executors的静态函数生成一个固定的U程池,思义Q线E池的线E是不会释放的,即它是Idle?br />
q就会生性能问题Q比如如果线E池的大ؓ200Q当全部使用完毕后,所有的U程会l留在池中,相应的内存和U程切换Qwhile(true)+sleep循环Q都会增加?br />
如果要避免这个问题,必ȝ接用ThreadPoolExecutor()来构造。可以像通用的线E池一栯|?#8220;最大线E数”?#8220;最线E数”?#8220;I闲U程keepAlive的时?#8221;?/p>
Semaphore 通常用于限制可以讉K某些资源Q物理或逻辑的)的线E数目。例如,下面的类使用信号量控制对内容池的讉KQ?/p>
q里是一个实际的情况Q大家排队上厕所Q厕所只有两个位置Q来?0个h需要排队?/p>
import java.util.concurrent.ExecutorService; public class MySemaphore extends Thread { ReentrantLock ReentrantLock 由最q成功获得锁定,q且q没有释放该锁定的线E所拥有。当锁定没有被另一个线E所拥有Ӟ调用 lock 的线E将成功获取该锁定ƈq回。如果当前线E已l拥有该锁定Q此Ҏ(gu)立卌回。可以?isHeldByCurrentThread() ?getHoldCount() Ҏ(gu)来检查此情况是否发生?/p>
此类的构造方法接受一个可选的公^参数?br />
当设|ؓ trueӞ在多个线E的争用下,q些锁定們于将讉K权授予等待时间最长的U程。否则此锁定无法保证Q何特定访问顺序?br />
与采用默认设|(使用不公q锁定)相比Q用公q锁定的E序在许多线E访问时表现为很低的M吞吐量(即速度很慢Q常常极其慢Q,但是在获得锁定和保证锁定分配的均衡性时差异较小。不q要注意的是Q公q锁定不能保证线E调度的公^性。因此,使用公^锁定的众多线E中的一员可能获得多倍的成功ZQ这U情况发生在其他zdU程没有被处理ƈ且目前ƈ未持有锁定时。还要注意的是,未定时的 tryLock Ҏ(gu)q没有用公q|。因为即使其他线E正在等待,只要该锁定是可用的,此方法就可以获得成功?/p>
L 立即实践Q?try 块来调用 lockQ在之前/之后的构造中Q最典型的代码如下: public void m() { 我的例子Q?br />
import java.util.concurrent.ExecutorService; public class MyReentrantLock extends Thread{ public static void main(String args[]){
newFixedThreadPoolQ?/strong>固定大小U程池)
创徏一个可重用固定U程集合的线E池Q以׃n的无界队列方式来q行q些U程Q只有要h的过来,׃在一个队列里{待执行Q。如果在关闭前的执行期间׃p|而导致Q何线E终止,那么一个新U程代替它执行后箋的Q务(如果需要)?/p>
创徏一个可Ҏ(gu)需要创建新U程的线E池Q但是在以前构造的U程可用时将重用它们。对于执行很多短期异步Q务的E序而言Q这些线E池通常可提高程序性能。调?execute 重用以前构造的U程Q如果线E可用)。如果现有线E没有可用的Q则创徏一个新U程q添加到池中。终止ƈ从缓存中U除那些已有 60 U钟未被使用的线E。因此,长时间保持空闲的U程池不会用Q何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但l节不同Q例如超时参敎ͼ的线E池?/p>
创徏一个用单?worker U程?ExecutorQ以无界队列方式来运行该U程。(注意Q如果因为在关闭前的执行期间出现p|而终止了此单个线E,那么如果需要,一个新U程代替它执行后箋的Q务)。可保证序地执行各个Q务,q且在Q意给定的旉不会有多个线E是zd的。与其他{效?newFixedThreadPool(1) 不同Q可保证无需重新配置此方法所q回的执行程序即可用其他的U程?/p>
import java.util.concurrent.Executors;
private int index;
public MyExecutor(int i){
this.index=i;
}
public void run(){
try{
System.out.println("["+this.index+"] start....");
Thread.sleep((int)(Math.random()*1000));
System.out.println("["+this.index+"] end.");
}
catch(Exception e){
e.printStackTrace();
}
}
public static void main(String args[]){
ExecutorService service=Executors.newFixedThreadPool(4);
for(int i=0;i<10;i++){
service.execute(new MyExecutor(i));
//service.submit(new MyExecutor(i));
}
System.out.println("submit finish");
service.shutdown();
}
}
q个是U程池基本用法?br />
Semaphore
一个计C号量。从概念上讲Q信号量l护了一个许可集合。如有必要,在许可可用前会阻塞每一?acquire()Q然后再获取该许可。每?release() d一个许可,从而可能释放一个正在阻塞的获取者。但是,不用实际的许可对象QSemaphore 只对可用许可的号码进行计敎ͼq取相应的行动?/p>
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
Semaphore position;
private int id;
public MySemaphore(int i,Semaphore s){
this.id=i;
this.position=s;
}
public void run(){
try{
if(position.availablePermits()>0){
System.out.println("֮["+this.id+"]q入厕所Q有IZ");
}
else{
System.out.println("֮["+this.id+"]q入厕所Q没IZQ排?);
}
position.acquire();
System.out.println("֮["+this.id+"]获得坑位");
Thread.sleep((int)(Math.random()*1000));
System.out.println("֮["+this.id+"]使用完毕");
position.release();
}
catch(Exception e){
e.printStackTrace();
}
}
public static void main(String args[]){
ExecutorService list=Executors.newCachedThreadPool();
Semaphore position=new Semaphore(2);
for(int i=0;i<10;i++){
list.submit(new MySemaphore(i+1,position));
}
list.shutdown();
position.acquireUninterruptibly(2);
System.out.println("使用完毕Q需要清扫了");
position.release(2);
}
}
一个可重入的互斥锁?LockQ它h与?synchronized Ҏ(gu)和语句所讉K的隐式监视器锁定相同的一些基本行为和语义Q但功能更强大?/p>
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
TestReentrantLock lock;
private int id;
public MyReentrantLock(int i,TestReentrantLock test){
this.id=i;
this.lock=test;
}
public void run(){
lock.print(id);
}
ExecutorService service=Executors.newCachedThreadPool();
TestReentrantLock lock=new TestReentrantLock();
for(int i=0;i<10;i++){
service.submit(new MyReentrantLock(i,lock));
}
service.shutdown();
}
}
class TestReentrantLock{
private ReentrantLock lock=new ReentrantLock();
public void print(int str){
try{
lock.lock();
System.out.println(str+"获得");
Thread.sleep((int)(Math.random()*1000));
}
catch(Exception e){
e.printStackTrace();
}
finally{
System.out.println(str+"释放");
lock.unlock();
}
}
}
]]>
首先是构造函数。以最单的构造函Cؓ例:
view plaincopy to clipboardprint?
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
看v来挺复杂的。这里介l一下?/p>
corePoolSize 指的是保留的U程池大?
maximumPoolSize 指的是线E池的最大大?
keepAliveTime 指的是空闲线E结束的时旉?
unit 是一个枚举,表示 keepAliveTime 的单位?
workQueue 表示存放d的队列?/p>
我们可以从线E池的工作过E中了解q些参数的意义。线E池的工作过E如下:
1、线E池刚创建时Q里面没有一个线E。Q务队列是作ؓ参数传进来的。不q,q队列里面有Q务,U程池也不会马上执行它们?/p>
2、当调用 execute() Ҏ(gu)d一个Q务时Q线E池会做如下判断Q?/p>
a. 如果正在q行的线E数量小?corePoolSizeQ那么马上创建线E运行这个Q务;
b. 如果正在q行的线E数量大于或{于 corePoolSizeQ那么将q个d攑օ队列?/p>
c. 如果q时候队列满了,而且正在q行的线E数量小?maximumPoolSizeQ那么还是要创徏U程q行q个dQ?/p>
d. 如果队列满了Q而且正在q行的线E数量大于或{于 maximumPoolSizeQ那么线E池会抛出异常,告诉调用?#8220;我不能再接受d?#8221;?/p>
3、当一个线E完成Q务时Q它会从队列中取下一个Q务来执行?/p>
4、当一个线E无事可做,过一定的旉QkeepAliveTimeQ时Q线E池会判断,如果当前q行的线E数大于 corePoolSizeQ那么这个线E就被停掉。所以线E池的所有Q务完成后Q它最l会收羃?corePoolSize 的大?/p>
q样的过E说明,q不是先加入d׃定会先执行。假N列大ؓ 10QcorePoolSize ?3QmaximumPoolSize ?6Q那么当加入 20 个Q务时Q执行的序是q样的:首先执行d 1??Q然后Q?4~13 被放入队列。这时候队列满了,d 14?5?6 会被马上执行Q而Q?17~20 则会抛出异常。最l顺序是Q????4?5?6???????0?1?2?3。下面是一个线E池使用的例子:
view plaincopy to clipboardprint?
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue);
for (int i = 0; i < 20; i++) {
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("thread %d finished", this.hashCode()));
}
});
}
executor.shutdown();
}
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue);
for (int i = 0; i < 20; i++) {
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("thread %d finished", this.hashCode()));
}
});
}
executor.shutdown();
}
对这个例子的说明如下Q?/p>
1、BlockingQueue 只是一个接口,常用的实现类?LinkedBlockingQueue ?ArrayBlockingQueue。用 LinkedBlockingQueue 的好处在于没有大限制。这L(fng)话,因ؓ队列不会满,所?execute() 不会抛出异常Q而线E池中运行的U程C永远不会过 corePoolSize 个,keepAliveTime 参数也就没有意义了?/p>
2、shutdown() Ҏ(gu)不会d。调?shutdown() Ҏ(gu)之后Q主U程马上结束了Q而线E池会l运行直到所有Q务执行完才会停止。如果不调用 shutdown() Ҏ(gu)Q那么线E池会一直保持下去,以便随时d新的d?/p>
到这里对于这个线E池q只是介l了一部分。ThreadPoolExecutor h很强的可扩展性,不过扩展它的前提是要熟?zhn)它的工作方式。后面的文章会介绍如何扩展 ThreadPoolExecutor cR?/p>
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/YidingHe/archive/2009/02/14/3889785.aspx
1QDOM(JAXP Crimson解析?
DOM是用与^台和语言无关的方式表CXML文档的官方W3C标准。DOM是以层次l构l织的节Ҏ(gu)信息片断的集合。这个层ơ结构允许开发h员在?wi)中L 特定信息。分析该l构通常需要加载整个文档和构造层ơ结构,然后才能做Q何工作。由于它是基于信息层ơ的Q因而DOM被认为是Z?wi)或Z对象的。DOM 以及q义的基于树(wi)的处理具有几个优炏V首先,׃?wi)在内存中是持久的,因此可以修改它以便应用程序能?gu)据和l构作出更改。它q可以在M时候在?wi)中上?DQ而不是像SAX那样是一ơ性的处理。DOM使用h也要单得多?/font>
2QSAX
SAX处理的优炚w常类g媒体的优点。分析能够立卛_始,而不是等待所有的数据被处理。而且Q由于应用程序只是在d数据时检查数据,因此不需要将?据存储在内存中。这对于大型文档来说是个巨大的优炏V事实上Q应用程序甚至不必解析整个文档;它可以在某个条g得到满时停止解析。一般来_SAXq比 它的替代者DOM快许多?
选择DOMq是选择SAXQ?对于需要自q写代码来处理XML文档的开发h员来_ 选择DOMq是SAX解析模型是一个非帔R要的设计决策?DOM采用建立?wi)Şl构的方式访问XML文档Q而SAX采用的事件模型?
DOM解析器把XML文档转化Z个包含其内容??wi),q可以对?wi)进行遍历。用DOM解析模型的优Ҏ(gu)~程Ҏ(gu)Q开发h员只需要调用徏?wi)的指oQ然后利用navigation APIs讉K所需的树(wi)节点来完成Q务。可以很Ҏ(gu)的添加和修改?wi)中的元素。然而由于用DOM解析器的时候需要处理整个XML文档Q所以对性能和内存的?求比较高Q尤其是遇到很大的XML文g的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频J的改变的服务中?
SAX解析器采用了Z事g的模型,它在解析 XML文档的时候可以触发一pd的事Ӟ当发现给定的tag的时候,它可以激zM个回调方法,告诉该方法制定的标签已经扑ֈ。SAX对内存的要求通常会比 较低Q因为它让开发h员自己来军_所要处理的tag。特别是当开发h员只需要处理文档中所包含的部分数据时QSAXq种扩展能力得到了更好的体现。但?SAX解析器的时候编码工作会比较困难Q而且很难同时讉K同一个文档中的多处不同数据?
3QJDOM http://www.jdom.org/
JDOM的目的是成ؓJava特定文档模型Q它化与XML的交互ƈ且比使用DOM实现更快。由于是W一个Java特定模型QJDOM一直得到大力推q和 促进。正在考虑通过“Java规范hJSR-102”它最l用?#8220;Java标准扩展”。从2000q初已l开始了JDOM开发?
JDOM与DOM主要有两斚w不同。首先,JDOM仅用具体类而不使用接口。这在某些方面简化了APIQ但是也限制了灵zL。第二,API大量使用了Collectionsc,化了那些已经熟?zhn)q些cȝJava开发者的使用?
JDOM文档声明其目的是“使用20%(或更? 的精力解?0%(或更?Java/XML问题”(Ҏ(gu)学习(fn)曲线假定?0%)。JDOM对于大多数Java/XML应用E序来说当然是有用的Qƈ且大 多数开发者发现API比DOMҎ(gu)理解得多。JDOMq包括对E序行ؓ的相当广泛检查以防止用户做Q何在XML中无意义的事。然而,它仍需要?zhn)充分理?XML以便做一些超出基本的工作(或者甚至理解某些情况下的错?。这也许是比学习(fn)DOM或JDOM接口都更有意义的工作?
JDOM自n不包含解析器。它通常使用SAX2?析器来解析和验证输入XML文档(管它还可以以前构造的DOM表示作ؓ输入)。它包含一些{换器以将JDOM表示输出成SAX2事g、DOM模型?XML文本文档。JDOM是在Apache许可证变体下发布的开放源码?/font>
4QDOM4J http://dom4j.sourceforge.net/
虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一U智能分支。它合ƈ了许多超出基本XML文档表示的功能,包括集成的XPath支持?XML Schema支持以及用于大文档或化文档的基于事件的处理。它q提供了构徏文档表示的选项Q它通过DOM4J API和标准DOM接口hq行讉K功能。从2000下半q开始,它就一直处于开发之中?
为支持所有这些功能,DOM4J使用接口和抽象基 本类Ҏ(gu)。DOM4J大量使用了API中的Collectionsc,但是在许多情况下Q它q提供一些替代方法以允许更好的性能或更直接的编码方法。直?好处是,虽然DOM4J付出了更复杂的API的代P但是它提供了比JDOM大得多的灉|性?
在添加灵zL、XPath集成和对大文档处理的?标时QDOM4J的目标与JDOM是一L(fng)Q针对Java开发者的易用性和直观操作。它q致力于成ؓ比JDOM更完整的解决Ҏ(gu)Q实现在本质上处理所?Java/XML问题的目标。在完成该目标时Q它比JDOM更少防止不正的应用E序行ؓ?
DOM4J是一个非帔R怼U的Java XML APIQ具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的Y件。如今你可以看到来多的Java软g都在使用DOM4J来读?XMLQ特别值得一提的是连Sun的JAXM也在用DOM4J?
2.. 比较
1QDOM4J性能最好,qSun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4JQ例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文g。如果不考虑可移植性,那就采用DOM4J.
2QJDOM和DOM在性能试时表C佻I在测?10M文档时内存溢出。在文档情况下q值得考虑使用DOM和JDOM。虽然JDOM的开发者已l说明他们期望在正式发行版前专注性能问题Q但是从性能?Ҏ(gu)看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现q泛应用于多U编E语a。它q是许多其它与XML相关的标准的基础Q因?它正式获得W3C推荐(与基于非标准的Java模型相对)Q所以在某些cd的项目中可能也需要它(如在JavaScript中用DOM)?/font>
3QSAX表现较好Q这要依赖于它特定的解析方式Q事仉动。一个SAX即到来的XML,但ƈ没有载入到内?当然当XML被dӞ会有部分文档暂时隐藏在内存中)?/font>
3. 四种xml操作方式的基本用方?/font>
xml文gQ?/font>
<?xml version="1.0" encoding="utf-8" ?>
<Result>
<VALUE>
<NO DATE="2005">A1</NO>
<ADDR>GZ</ADDR>
</VALUE>
<VALUE>
<NO DATE="2004">A2</NO>
<ADDR>XG</ADDR>
</VALUE>
</Result>
1QDOM
import java.io.*;
import java.util.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
public class MyXMLReader{
public static void main(String arge[]){
long lasting =System.currentTimeMillis();
try{
File f=new File("data_10k.xml");
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc = builder.parse(f);
NodeList nl = doc.getElementsByTagName("VALUE");
for (int i=0;iQnl.getLength();i++){
System.out.print("车牌L(fng):" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());
System.out.println("车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());
}
}catch(Exception e){
e.printStackTrace();
}
2QSAX
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
public class MyXMLReader extends DefaultHandler {
java.util.Stack tags = new java.util.Stack();
public MyXMLReader() {
super();
}
public static void main(String args[]) {
long lasting = System.currentTimeMillis();
try {
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sp = sf.newSAXParser();
MyXMLReader reader = new MyXMLReader();
sp.parse(new InputSource("data_10k.xml"), reader);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("q行旉Q? + (System.currentTimeMillis() - lasting) + "毫秒");}
public void characters(char ch[], int start, int length) throws SAXException {
String tag = (String) tags.peek();
if (tag.equals("NO")) {
System.out.print("车牌L(fng)Q? + new String(ch, start, length));
}
if (tag.equals("ADDR")) {
System.out.println("地址:" + new String(ch, start, length));
}
}
public void startElement(String uri,String localName,String qName,Attributes attrs) {
tags.push(qName);}
}
3Q?JDOM
import java.io.*;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;
public class MyXMLReader {
public static void main(String arge[]) {
long lasting = System.currentTimeMillis();
try {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("data_10k.xml"));
Element foo = doc.getRootElement();
List allChildren = foo.getChildren();
for(int i=0;iQallChildren.size();i++) {
System.out.print("车牌L(fng):" + ((Element)allChildren.get(i)).getChild("NO").getText());
System.out.println("车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText());
}
} catch (Exception e) {
e.printStackTrace();
}
}
4QDOM4J
import java.io.*;
import java.util.*;
import org.dom4j.*;
import org.dom4j.io.*;
public class MyXMLReader {
public static void main(String arge[]) {
对于我们常用的GBK中,英文是占?个字节,中文??
对于UTF-8Q英文是1个,中文??
对于UnicodeQ英文中文都??/span>
Java的流操作分ؓ字节和字符两U?/span>
1?nbsp;字节?/span>
所有的L作都l承自一个公pc?span style="font-family: Times New Roman">java.io.InputStreamcR?/span>
所有的写操作都l承自一个公pc?span style="font-family: Times New Roman">java.io.OutputStreamcR?/span>
InputStream?span style="font-family: Times New Roman">OutputStream都是抽象cR?/span>
InputStream?span style="font-family: Times New Roman">6个低U输入流Q?/span>
低?/span> |
的用?/span> |
ByteArrayInputStream |
从内存数l中d数据字节 |
FileInputStream |
从本地文件系l中d数据字节 |
PipedInputStream |
从线E管道中d数据字节 |
StringBufferInputStream |
从字W串中读取数据字?/span> |
SequenceInputStream |
从两个或多个低中d数据字节Q当到达的末尾时从一个流转到另一个流 |
System.in |
从用h制台d数据字节 |
InputStreamq有一个子c:qo器流java.io.FilterInputStream。过滤器即能把基本包裹v来,提供更多方便的用法?/span>
FilterInputStream cȝ构造方法ؓFilterInputStream(InputStream)Q在指定的输入流之上Q创Z个输入流qo器?/span>
FilterInputStream的常用的子类如下Q?/span>
qo器输入流 |
的用?/span> |
BufferedInputStream |
~冲区对数据的访问,以提高效?/span> |
DataInputStream |
从输入流中读取基本数据类型,?span style="font-family: Times New Roman">int?span style="font-family: Times New Roman">float?span style="font-family: Times New Roman">double或者甚至一行文?/span> |
LineNumberInputStream |
在翻译行l束W的基础上,l护一个计数器Q该计数器表明正在读取的是哪一行?/span> |
PushbackInputStream |
允许把数据字节向后推到流的首?/span> |
OutputStreamQ略Q?/span>
OutputStream的结构基本和InputStream是一L(fng)?/span>
2?nbsp;字符?/span>
注:是在jdk1.1里面引进的,上面字节是?span style="font-family: Times New Roman">jdk1.0引进的。当用于处理文本数据Ӟ选择字符比字节更好。但对只\基本数据cd的开发者,可以l箋使用字节?/span>
所有的L作都l承自一个公pc?span style="font-family: Times New Roman">java.io.ReadercR?/span>
所有的写操作都l承自一个公pc?span style="font-family: Times New Roman">java.io.WritercR?/span>
同样Reader?span style="font-family: Times New Roman">Writer也是抽象cR?/span>
Reader的常用的子类如下Q?/span>
低d?/span> |
的用?/span> |
CharArrayReader |
从字W数l中d数据 |
InputStreamReader
|
|
FileReaderQInputStreamReader的子c)
|
从本地文件系l中d字符序列 |
StringReader |
从字W串中读取字W序?/span> |
PipedReader |
从线E管道中d字符序列 |
InputStreamReader重点讲解Q?/p>
InputStreamReader是从输入中d数据Q连接输入流于读取器。如Q?/p>
new InputStreamReader(System.in)
构造方法:
InputStreamReader(InputStream)
用缺省的字符~码方式Q创Z?InputStreamReader?/p>
InputStreamReader(InputStream, String)
用已命名的字W编码方式,创徏一?InputStreamReader?/p>
常用的过滤器d器:
qo器读取器
|
的用?/span> |
BufferedReader |
~冲数据的访问,以提高效?/span> |
LineNumberReaderQ?span style="font-family: Times New Roman">BufferedReader的子c) |
l护一个计数器Q该计数器表明正在读取的是哪一行?/span> |
FilterReaderQ抽象类Q?/span> |
提供一个类创徏qo器时可以扩展q个c?/span> |
PushbackReaderQ?span style="font-family: Times New Roman">FilterReader的子c) |
允许把文本数据推回到d器的中 |
q些qo器读取器都可以传入一?span style="font-size: 12pt">Reader作ؓ构造方法的参数?/p>
WriterQ略Q?/p>
Writer的结构基本和Reader是一L(fng)?/span>
字节是最基本的,字符是Z处理字符而提出来的?/span>
new BufferedReader(new InputStreamReader(client.getInputStream()));解释Q?/span>
client.getInputStream()是字节流Q?/span>
InputStreamReader把字节流转换成字W流Q?/span>
BufferedReader~冲字符,使得能够使用readline(){方法,直接d一行?/span>
1.什么是TransactionQ所谓Transaction是指一pd不可分割的改动数据库的操作。在q个解释中,有三个关键词Q一pdQ不可分割以及改动。仅仅是一个改动数据库的操作是没有Transaction可言Q只?#8220;一pd”操作(一lSQL语句)才可能组成TransactionQ?#8220;不可分割”意味着一致性和完整性,要么q一pd操作全部commitQ要么就全部rollbackQ如果一pd的操作只包含enquiry操作Q那么这些操作也不是Transaction?nbsp;
2.在J2EE中,Transaction主要有几大类Q具体有几种Q在J2EE中,Transaction主要有Bean-Managed Transaction和Container-Managed Transaction两大cR其中在Bean-Managed Transaction中还会分为JDBC Transaction和JTA Transaction两种?/p>
3.什么是JDBC TransactionQ它有怎样的特点?JDBC Transaction是指由Database本nȝ理的事务。其最大的特点是通过昄调用Connection接口的commit和rollbackҎ(gu)来完成事务的提交和回滚。事务结束的边界是commit或者rollbackҎ(gu)的调用,而开始的边界则不是那么明显了Q它会开始于l成当前事务的所有statement中的W一个被执行的时候。具体代码如下:
class CreditDAoImpl implements CreditDAO
{
Connection conn = getConnection();
public void transfer(Currency amount, Account fromAccount, Account toAccount) throws CreditException
{
try
{
conn.setAutoCommit(false);
depositToAccount(conn, toAccount, amount);
withdrawFromAccount(conn, fromAccount, amount);
conn.commit();
} catch (Exception e)
{
try
{
conn.rollback();
throw new CreditException(e.getMessage());
} catch (SQLException e1)
{
throw new CreditException(e.getMessage());
}
}
}
}
4.什么是JTA TransactionQ它有怎样的特点呢QJTA Transaction是指由J2EE Transaction managerȝ理的事务。其最大的特点是调用UserTransaction接口的beginQcommit和rollbackҎ(gu)来完成事务范围的界定Q事务的提交和回滚。JTA Transaction可以实现同一事务对应不同的数据库Q但是它仍然无法实现事务的嵌套。具体的代码如下[1]Q?/p>
public void withdrawCash(double amount)
{
UserTransaction ut = context.getUserTransaction();
try
{
ut.begin();
updateChecking(amount);
machineBalance -= amount;
insertMachine(machineBalance);
ut.commit();
} catch (Exception ex)
{
try
{
ut.rollback();
} catch (SystemException syex)
{
throw new EJBException
("Rollback failed: " + syex.getMessage());
}
throw new EJBException
("Transaction failed: " + ex.getMessage());
}
}
5.什么是Container-Managed TransactionQ它又有怎样的特点呢QContainer-Managed TransactionQ顾名思义Q就是由Container负责理的TransactionQ当然这样Transaction是出现在EJB的范畴中。Container-Managed Transaction最大的特点是不需要显式界定事务的边界Q也不需要显式的提交或者回滚事务,q一切都由Container来替我们完成。我们需要做的就是设定在一个Bean中,哪些Ҏ(gu)是跟事务相关的,同时讑֮它们的Transaction Attribute既可?/p>
Transaction的Scope是相当重要的Q特别是在一个Bean的方法中调用另外一个Bean的方法。ؓ了便于说明问题,我们把这两个Ҏ(gu)分别UCؓmethodA和methodB。当methodA调用methodB的时候,methodB在事务的层面上对调用者methodA有怎样的限?methodB中是否存在事?以及methodA如何在事务的层面上实现对methodB的调?是否需要重新创Z个新的事务来处理methodB的调?都需要通过Transaction Attribute来设定的。具体的Transaction Attribute有以下六U:RequiredQRequiresNewQMandatoryQNotSupportedQSupports和Never。有关Transaction Attribute的介l,可以参阅J2EE Tutorial?a >关于Container-Managed Transaction的介l?/a>?/p>
[1] 代码来自SUN的J2EE Tutorial中关?a >Bean-Managed Transaction的介l?
private TransactionManager getFromJNDI()
throws Exception {
InitialContext ctx = new InitialContext();
try {
// WebLogic
return (TransactionManager)
ctx.lookup("javax.transaction.TransactionManager");
}
catch (Exception e) { }
try {
// JBoss
return (TransactionManager)
ctx.lookup("java:/TransactionManager");
}
catch (Exception e) { }
return null;
}
public TransactionManager getFromWebsphereFactory()
throws Exception{
try{
// WebSphere 5.1 or 6.0
return
com.ibm.ws.Transaction.TransactionManagerFactory
.getTransactionManager();
}
catch (ClassNotFoundException ex){}
try{
// WebSphere 5.0
return
com.ibm.ejs.jts.jta.TransactionManagerFactory
.getTransactionManager();
}
catch (ClassNotFoundException ex){}
try{
// WebSphere 4.0
com.ibm.ejs.jts.jta.JTSXA..getTransactionManager();
}
catch (ClassNotFoundException ex){ }
return null;
}
刚刚开始学?fn)JBossQ学?fn)了一个入门的小例子Q对于刚接触JBoss和Eclipse的菜鸟来说很有帮助的Q现在把我的试验q程介绍一下?br />
首先Q打开EclipseQ新建——其它——JBoss IDE——J2EE Projects——J2EE 1.4 Projects
下一?br />
填入目名称QHelloWorld
目内容可以选择使用~省值或者自己制定存储空?br />
下一?br />
在源选单下,d文g夹,分别命名为j2srcQ存放java文gQ和srcQ存N|文ӞQ缺省输出文件夹改ؓQHelloWorld/bin
完成
在包资源理器中Q右键单击j2srcQ选择新徏——包Q输入包名:sample.server?/font>
右键单击sample.serverQ选择新徏——接口,输入接口名字QHelloWorldQ此E接口,是指对于客户端而言所能看到的调用接口Q该接口内容为:
/**
*HelloWorld.java
*/
package sample.server;
import javax.ejb.EJBObject;
/**
* @author Administrator
*
* TODO 要更Ҏ(gu)生成的类型注释的模板Q请转至
* H口 Q?首选项 Q?Java Q?代码样式 Q?代码模板
*/
public interface HelloWorld extends EJBObject {
public String hello() throws java.rmi.RemoteException;
}
同样的,新徏Home接口HelloWorldHomeQ我们可以把Home接口看做是一个制造EJB的工厂,它告诉EJB容器Q?#8220;我的客户要我生成一个EJBQ现在我把这个Q务交l你啦!”
/**
* HelloWorldHome.java
*/
package sample.server;
import javax.ejb.EJBHome;
/**
* @author Administrator
*
* TODO 要更Ҏ(gu)生成的类型注释的模板Q请转至
* H口 Q?首选项 Q?Java Q?代码样式 Q?代码模板
*/
public interface HelloWorldHome extends EJBHome {
HelloWorld create() throws java.rmi.RemoteException,
javax.ejb.CreateException;
}
下面是EJB的实玎ͼ右键单击sample.serverQ新建——其它——JBoss IDE——EJB Components——Session BeanQ输入名UͼHelloWorldBeanQ类型ؓStatelessQRemoteQ选择创徏来自类的构造函敎ͼl承的抽象方法,ejbCreate() method。完成?/font>
/**
* HelloWorldBean.java
*/
package sample.server;
import java.rmi.RemoteException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.CreateException;
/**
* @ejb.bean name="HelloWorld"
* display-name="Name for HelloWorld"
* description="Description for HelloWorld"
* jndi-name="ejb/HelloWorld"
* type="Stateless"
* view-type="remote"
*/
public class HelloWorldBean implements SessionBean {
/**
*
*/
public HelloWorldBean() {
super();
// TODO 自动生成构造函数存?br />
}
/* Q非 JavadocQ?br />
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
*/
public void setSessionContext(SessionContext ctx)
throws EJBException,
RemoteException {
// TODO 自动生成Ҏ(gu)存根
}
/* Q非 JavadocQ?br />
* @see javax.ejb.SessionBean#ejbRemove()
*/
public void ejbRemove() throws EJBException, RemoteException {
// TODO 自动生成Ҏ(gu)存根
}
/* Q非 JavadocQ?br />
* @see javax.ejb.SessionBean#ejbActivate()
*/
public void ejbActivate() throws EJBException, RemoteException {
// TODO 自动生成Ҏ(gu)存根
}
/* Q非 JavadocQ?br />
* @see javax.ejb.SessionBean#ejbPassivate()
*/
public void ejbPassivate() throws EJBException, RemoteException {
// TODO 自动生成Ҏ(gu)存根
}
/**
* Default create method
*
* @throws CreateException
* @ejb.create-method
*/
public void ejbCreate() throws CreateException {
// TODO Auto-generated method stub
}
public String hello()
{
System.out.println("hello()");
return "Hello,world";
}
}
服务器端E序~好Q下一步就要做部v工作了?/font>
右键选择srcQ新建目录META-INFQ在该目录下Q新建——其它——JBoss-IDE——Descriptors——EJB 2.1 Deployment DescriptorQ默认名字ؓejb-jar.xmlQ完成?br /> ejb-jar.xmlQ?/font>
?xml version="1.0" encoding="UTF-8"??br />
《ejb-jar version="2.1"
xmlns="
xmlns:xsi="
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
《ejb-jar?br />
《enterprise-beans?br />
《session?br />
《ejb-name》HelloWorldBean?ejb-name?br />
《home》sample.server.HelloWorldHome?home?br />
《remote》sample.server.HelloWorld?remote?br />
《ejb-class》sample.server.HelloWorldBean?ejb-class?br />
《session-type》Stateful?session-type?br />
《transaction-type》Bean?transaction-type?br />
?session?br />
?enterprise-beans?br />
?ejb-jar?/font>
Q备注:在此Q由于网|C的原因Q将<>W号Ҏ(gu)了《》,所以,在实际应用中应改?lt;>Q以正常工作。同Ӟejb-jar.xml开头的版本标记文字会因jboss版本不同而不同,希望大家注意Q?!--l version="1.0" encoding="UTF-8-->
q样我们完成了一个简单的会话EJB的编写,下一步是打包?br /> 同时选择j2src和src两个目录Q右键单击选择导出——jar——选择导出目标Q可以放在定义的HelloWorld目录下,起个名字叫HelloWorld.jarQ则会在包资源管理器中看C个文件HelloWorld.jar?/font>
光有EJBQ没有客L(fng)Q对我们来说毫无用处Q所以下一步我们就要编写客L(fng)E序?br />
同样的,在j2src下创建包sample.client?br />
在该包下新徏c,cd为HelloWorldClientQ添加接口:sample.server.HelloWorldQ?br />
/**
* HelloWorldClient.java
*/
sample.server.HelloWorldHome?/font>
package sample.client;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import sample.server.HelloWorld;
import sample.server.HelloWorldHome;
/**
* @author Administrator
*
* TODO 要更Ҏ(gu)生成的类型注释的模板Q请转至
* H口 Q?首选项 Q?Java Q?代码样式 Q?代码模板
*/
public class HelloWorldClient{
public static void main(String [] args){
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
env.put(Context.PROVIDER_URL,"localhost:1099");
/**
* 默认是把服务器端EJB部v在本ZQ如果部|在其它机器上,比如192.168.0.1Q则localhost * 改ؓ192.168.0.1卛_
*/
env.put("Java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
try{
Context ctx = new InitialContext(env);
Object obj = ctx.lookup("HelloWorldBean");
HelloWorldHome home =(HelloWorldHome)javax.rmi.PortableRemoteObject.narrow(
obj, HelloWorldHome.class );
HelloWorld helloWorld = home.create();
System.out.println(helloWorld.hello());
helloWorld.remove();
}catch(Exception e){
e.printStackTrace();
System.out.println("Exception:"+e.getMessage());
}
}
}
下面可以编译运行了?br />
手动启动JBossQ直接运行JBoss\bin\目录下的run.bat卛_Q这个过E时间长短跟计算机的配置有关Q配|高的计机几秒钟就可以了,比较传统的计机则需要等?分多钟甚x长,不过你不需要专门等着它的q行Q你双击run.bat后,不用它Q你可以先做一些其他的事情Q比如给mm发条短信啊什么的Q等你发完短信后Q你会发现JBoss已经q行成功Qƈ会告诉你启动JBoss׃多长旉QStarted in 1m:36s:870msQ呵呵,我的机器比较传统哈?br />
选择包资源管理器中的HelloWorld.jarQ右键单击选择Deployment——Deploy toQ?br />
选择jboss 4.0(default)[file:/D:/jboss4/server/default/deploy/]
则系l会自动把HelloWorld.jar文g拯到jboss?server/default/deploy/目录下,jboss的运行窗口将出现
10:09:50,679 INFO [EjbModule] Deploying HelloWorldBean
10:09:52,051 INFO [org.jboss.ejb.EJBDeployer] Deployed: file:/D:/jboss4/server/default/deploy/HelloWorld.jar
服务器端q行成功
右键选择HelloWorldClient.javaQ选择q行——运行,在左辚w择java应用E序下的HelloWorldClientQ右辚w择c\径,在引导程序条目下d外部JARQ分别jboss的client目录下的jboss-j2ee.jar、log4j.jar、jboss-client.jar。然后单击运行,׃看到底下控制C昄?#8220;HelloQW(xu)orld”Q哈哈,成功了,q可跟一般的“HelloWorld”不太一样哦?/font>
JBoss Eclipse IDE主要支持J2EE的WEB和EJB开发,实则提供ant和xdoclet自动提示{方便功能,q提供Hibernate EJB 3.0 JBoss AOP{开发,内置Jsp~辑器。可实现J2EE模块打包和设定部|Ԍl合JBoss服务器进行调试等?/p>
安装JBoss Eclipse IDE到Eclipse中有两种方式Q注意Eclipse的插件安装非常注意版本,q是需要非常小心的Q?/p>
W一U:下蝲安装Q在|址http://www.jboss.org/products/jbosside下蝲
W二U:配置Eclipse的find and installQ将bookmark http://jboss.sourceforge.net/jbosside/updates
如果是Eclipse 3.0Q就下蝲支持3.0插gQ如果是Eclipse 3.1Q就下蝲支持3.1Q注意不能是3.1M8 {,后面有M的也不行?/p>
安装完成后,参考JBoss的开发指南一步步操作卛_Q?/p>
http://docs.jboss.com/jbosside/tutorial/build/en/html/
当然Q除了Eclipseq样的开发工P我们q需要事先搭建J2EEq行环境QJBoss+MySQLQ我们这个组合也UCؓEclipse+JBoss+MySQL无敌开源免费J2EE/EJB开发组合?)
Z辑ֈ熟练开发,xDoclet虽然由Eclipse配置后自动生成,但是有关JNDI调用需要手工写一些xDoclet标签Q?a target="_blank">dq篇文章http://www.devx.com/Java/Article/20578基本了解xDoclet了。剩余的是查xDcolet使用手册Q不q在开发时Q用Ctrl+Space按键可自动提C标{语法?/p>
在按照JBossIDE开发指南开发这样一个J2EE应用Ӟ有些问题需要自p冻I如没有MANIFEST.MF需要自己创Z个;application.xml中需要手工写正确{。MQ前提需要对WEB或EJB知识有一个了解,知道哪些问题属于J2EE问题Q哪些属于自q_心问题?/p>
我已l开发了一个Web+EJB的J2EE例程源码?a target="_blank">VIP教程?/a>,其中Session是用LocalQ而非remote。用Local在一台服务器里运行时Q性能比较快?/p>