JunXiu

2010年8月19日

为了解答“正则表达式(/[^0-9]/g,'')中的"/g"是什么意思?”这个问题,也为了能够便于大家对正则表达式有一个更为综合和深刻的认识,我将一些关键点和容易犯糊涂的地方再系统总结一下。

总结1:附件参数g的用法

表达式加上参数g之后,表明可以进行全局匹配,注意这里“可以”的含义。我们详细叙述:

1)对于表达式对象的exec方法,不加入g,则只返回第一个匹配,无论执行多少次均是如此,如果加入g,则第一次执行也返回第一个匹配,再执行返回第二个匹配,依次类推。例如
var regx=/user\d/;
var str=“user18dsdfuser2dsfsd”;
var rs=regx.exec(str);//此时rs的值为{user1}
var rs2=regx.exec(str);//此时rs的值依然为{user1}
如果regx=/user\d/g;则rs的值为{user1},rs2的值为{user2}
通过这个例子说明:对于exec方法,表达式加入了g,并不是说执行exec方法就可以返回所有的匹配,而是说加入了g之后,我可以通过某种方式得到所有的匹配,这里的“方式”对于exec而言,就是依次执行这个方法即可。

2)对于表达式对象的test方法,加入g于不加上g没有什么区别。

3)对于String对象的match方法,不加入g,也只是返回第一个匹配,一直执行match方法也总是返回第一个匹配,加入g,则一次返回所有的匹配(注意这与表达式对象的exec方法不同,对于exec而言,表达式即使加上了g,也不会一次返回所有的匹配)。例如:
var regx=/user\d/;
var str=“user1sdfsffuser2dfsdf”;
var rs=str.match(regx);//此时rs的值为{user1}
var rs2=str.match(regx);//此时rs的值依然为{user1}
如果regx=/user\d/g,则rs的值为{user1,user2},rs2的值也为{user1,user2}

4)对于String对象的replace方法,表达式不加入g,则只替换第一个匹配,如果加入g,则替换所有匹配。(开头的三道测试题能很好的说明这一点)

5)对于String对象的split方法,加上g与不加g是一样的,即:
var sep=/user\d/;
var array=“user1dfsfuser2dfsf”.split(sep);
则array的值为{dfsf, dfsf}
此时sep=/user\d/g,返回值是一样的。

6)对于String对象的search方法,加不加g也是一样的。

总结2:附加参数m的用法

附加参数m,表明可以进行多行匹配,但是这个只有当使用^和$模式时才会起作用,在其他的模式中,加不加入m都可以进行多行匹配(其实说多行的字符串也是一个普通字符串),我们举例说明这一点

1)使用^的例子
var regx=/^b./g;
var str=“bd76 dfsdf
sdfsdfs dffs
b76dsf sdfsdf”;
var rs=str.match(regx);
此时加入g和不加入g,都只返回第一个匹配{bd},如果regx=/^b./gm,则返回所有的匹配{bd,b7},注意如果regx=/^b./m,则也只返回第一个匹配。所以,加入m表明可以进行多行匹配,加入g表明可以进行全局匹配,综合到一起就是可以进行多行全局匹配

2)使用其他模式的例子,例如
var regx=/user\d/;
var str=“sdfsfsdfsdf
sdfsuser3 dffs
b76dsf user6”;
var rs=str.match(regx);
此时不加参数g,则返回{user3},加入参数g返回{user3,user6},加不加入m对此没有影响。

3)因此对于m我们要清楚它的使用,记住它只对^和$模式起作用,在这两种模式中,m的作用为:如果不加入m,则只能在第一行进行匹配,如果加入m则可以在所有的行进行匹配。我们再看一个^的例子
var regx=/^b./;
var str=“ret76 dfsdf
bjfsdfs dffs
b76dsf sdfsdf”;
var rs=str.match(regx);
此时rs的值为null,如果加入g,rs的值仍然为null,如果加入m,则rs的值为{bj}(也就是说,在第一行没有找到匹配,因为有参数m,所以可以继续去下面的行去找是否有匹配),如果m和g都加上,则返回{bj,b7}(只加m不加g说明,可以去多行进行匹配,但是找到一个匹配后就返回,加入g表明将多行中所有的匹配返回,当然对于match方法是如此,对于exec呢,则需要执行多次才能依次返回)

总结3:在HTML的textarea输入域中,按一个Enter键,对应的控制字符为“\r\n”,即“回车换行”,而不是“\n\r”,即“换行回车”,我们看一个前面我们举过的例子:
var regx=/a\r\nbc/;
var str=“a
bc”;
var rs=regx.exec(str);
结果:匹配成功,rs的值为:{ },如果表达式为/a\n\rbc/,则不会被匹配,因此在一般的编辑器中一个”Enter”键代表着“回车换行”,而非“换行回车”,至少在textarea域中是这样的。

posted @ 2010-12-30 17:45 junlin 阅读(191) | 评论 (0)编辑 收藏

作在工作中,经常需要远程连接到服务器上,然而在公司里,老总、同事都需要连接到服务器上的,而默认的Win2003操作系统最大连接数是2,这样一来,问题也就来了,常常遇到“终端服务器超出最大连接数”,导致无法正常登陆服务器。下面讲解在网上流传的几种方法,来解决这一问题。

解决方法一:用“注销”方式退出远程桌面,而不是直接关闭窗口;

解决方法二:踢出已经断开的连接用户;

1、首先通过各种方法连接到服务器上(telnet);

2、上去后,查看登陆用户列表。输入命令:query user;

这样你就可以看出有何不同来啦,可以根据你的具体情况而定的。ID为0的用户就是本地登陆的,而在State中看提示,当提示为已断开,则说明用户已经断开还占用着系统资源和通道,这样就可以把该用户踢掉。输入logoff ID,即踢除相应ID的用户。

解决方法三:限制已断开连接的会话存在时间;(推荐)

一般情况下,我们在维护远程服务器时,不可能长时间在线,但是系统默认的却是只要登录就不再断开。因此,我们可以修改这一默认设置,给它指定一个自动断开的时间即可。

可以在 Windows 2003 服务器上通过组策略中设置一下来解决问题:单击“开始 → 运行”,输入“gpedit.msc”,回车后打开组策略窗口,然后依次定位到“计算机配置 → 管理模板 → Windows 组件 → 终端服务 → 会话”,然后在右侧窗口中双击“为断开的会话设置时间限制”,在打开的窗口中将“结束断开连接的会话”时间设置为5分钟,或者设置为空闲就断开。或在远程服务器上打开“运行”窗口,输入“tscc.msc”连接设置窗口。然后双击“连接”项右侧的“RDP-Tcp”,切换到“会话”标签,选中“替代用户设置”选项,再给“结束已断开的会话”设置一个合适的时间即可。

解决方法四:增加连接数量,即设置最大连接数再多些;

默认情况下允许远程终端连接的数量是2个用户,我们可以根据需要适当增加远程连接同时在线的用户数。

单击“开始→运行”,输入 “gpedit.msc”打开组策略编辑器窗口,依次定位到“计算机配置 → 管理模板 → Windows 组件 → 终端服务”,再双击右侧的“限制连接数量”,将其TS允许的最大连接数设置大一些即可。

经过上面两个配置(方法三&方法四),基本上就可以保证远程终端连接时不再受限。但仍有人反映,当前同时只有一个用户进行连接,却提示超出最大允许链接数,这又是什么原因呢?出现这种情况是因为操作不当所造成的。在上一个帐户登录远程桌面后退出时,没有采用注销的方式,而是直接关闭远程桌面窗口,那么导致该会话并没有被释放,而是继续保留在服务器端,占用了连接数,这样就会影响下一个用户的正常登录了。

解决方法五:限制用户会话数;

对Terminal Services进行限制,使得一个用户仅仅能够连接一次。对于Windows Server 2003,请在Terminal Services Configuration(Terminal Services配置)中将“限制每位用户只有拥有一个会话”(Restrict each user to one session)设置为“是”(Yes)。此外,您可以将“限制终端服务用户使用单个远程会话”组策略设置为“启用”。

注意:版本不一样解决的方法有异!

A:这是因为Windows 2003中设置了最大允许连接数限制,而你每次连接后可能没有注销而是直接关闭,导致连接数超过了最大连接数。你可以在Windows 2003 服务器上通过组策略中设置一下来解决问题:单击“开始→运行”,输入 “gpedit.msc”,回车后打开组策略窗口,然后依次定位到“计算机配置 → 管理模板 → 终端服务 → 会话”,然后在右侧窗口中双击“为断开的会话设置时 间限制”,在打开的窗口中将“结束断开连接的会话”时间设置为5分钟。最好的解决方法还是你每次断开连接时通过注销的方式。

B:经常多人管理服务器的朋友一定遇到过当自己终端连接远程计算机的时候却提示“终端连接超出了最大连接”的提示吧?这是因为windows2003仅支持2个终端用户的登陆。当这种情况出现后,多数人选择的是给机房打电话进行重启服务器。可是带来的损失也是显而 易见的。那么我们有什么办法来解决呢?方法当然是有的。我们只需要在一台2003的机器上运行“tsmmc.msc”就可以打开远程桌面连接,在这里我们 添加一个新的连接,输入对方的IP地址帐号和密码后就可以成功登陆到对方的桌面中,这时可以再踢下一个用户。就可以解决终端连接数超过最大的问题。

C:开始 → 控制面版 → 授权里面更改连接数。

 

在命令行:
mstsc /console /v:你的服务器IP:远程端口

例如 :mstsc /console /v:222.222.215.222:3389

win2K/win2003终端服务器超出最大允许连接数解决之道全攻略
原因:用远程桌面链接登录到终端服务器时经常会遇到“终端服务器超出最大允许链接数”诸如此类错误导致无法正常登录终端服务器,引起该问题的原因在于终端服务的缺省链接数为2个链接,并且当登录远程桌面后如果不是采用注销方式退出,而是直接关闭远程桌面窗口,那么实际上会话并没有释放掉,而是继续保留在服务器端,这样就会占用总的链接数,当这个数量达到最大允许值时就会出现上面的提示。
如何避免?
一、用注销来退出远程桌面而不是直接关闭窗口二、限制已断开链接的会话存在时间
1、从终端服务配置中修改
运行-Tscc.msc(终端服务配置)-连接-双击RDP-Tcp或右击-属性-会话-选中第一个的替代用户设置(O)-结束已断开的会话[将默认值“从不”改为一个适当的时间,比如30分钟]
2、从组策略修改
开始-运行-gpedit.msc-计算机配置-管理模板-windows组件-终端服务-会话
右边窗口选择 为断开的会话设置时间限制 -选择已启用,选择一个时间
三、增加最多链接数
1、从终端服务配置中修改:运行-Tscc.msc(终端服务配置)-连接-双击RDP-Tcp或右击-属性,选择“网卡”选项卡-修改“最大连接数”改成你所需的值,当然这个值不也能太大,否则会占用较多的系统资源。不过这里修改的值好像不起作用,设置成无限制时照样还是会出现本文所说的情况。  
2、组策略级别要高于终端服务配置,当启用组策略后终端服务配置中的相应选项会变成灰色不可修改
运行-gpedit.msc-计算机配置-管理模板-Windows组件-终端服务
双击右边的”限制连接数量“-选择”已启用“-填入允许的最大连接数
四、改变远程终端模式
打开“控制面板”,双击“添加删除程序”,单击“添加删除Windows组件”,“组件”,在Windows组件向导对话框中选中“终端服务” , “下一步”,“应用服务器”,“下一步”,然后按照提示即可改变终端服务的模式。  
Windows 2000终端服务有2种运行模式: 远程管理模式和应用程序服务器模式。远程管理模式允许系统管理员远程管理服务器,而且只允许2个终端会话同时登录终端服务器。应用程序服务器模式允许用户运行一个以上应用程序,允许多个用户从终端登录访问服务器。但是,应用终端服务的用户必须有终端服务授权,即必须在90天之内在这个域或工作组中设置终端服务授权服务器,否则用户需删除应用程序,然后再重新安装。
五、修改本地安全策略
控制面板>>管理工具>>本地安全策略>>本地策略>>安全选项>>
1、先找到>>Microsoft网络服务器:在挂起会话之前所需的空闲时间
默认为:15分钟,改为自己所需要的时间(就是登陆后无动作空闲超过多少时间后自动断开)
2、然后找到>>网络安全:在超过登录时间后强制注销。默认为:已禁用,一定要改为:已启用
如果已经发生解决办法:
1、首先你可以telnet到此主机上(不管你用哪种方法),当然如果能直接操作机器更好,不过直接操作就不必用命令行了,那当然是知道机器超级管理员的密码的情况下,可以使用OpenTelnet来打开远程服务器的Telnet端口。
2、Telnet上去后,先看登陆的用户:
输入命令:query user
系统返回:
C:>query user
USERNAME        SESSIONNAME     ID    STATE     IDLE TIME    LOGON TIME
k12update       console         1     运行中         2007-3-14 14:57
此时可以看出的可能都不一样,根据具体情况而定。
ID 0 的用户是本地登陆的,ID 1 和 ID 12是3389登陆的用户,前者在运行中,后者已经断开了,但是断开了仍然占用系统资源和通道,我们要把它踢掉。如下进行操作即可。
输入命令:logoff 1
3、如果服务器关闭了telnet功能(这是默认的),还可以通过SqlServer的xp_cmdshell扩展存储过程,使用格式:master.dbo.xp_cmdshell '命令内容',其余可参考第二步。此方式要求有访问xp_cmdshell的权限
上面的办法基本没有用

[原创经典]“终端服务器超出了最大允许连接数”的解决办法

2007-04-25 17:13

现象及原因:用远程桌面连接登录到终端服务器时经常会遇到“终端服务器超出最大允许连接数”诸如此类错误导致无法正常登录终端服务器,引起该问题的原因在于Windows Server 2003中设置终端服务的缺省连接数为2个链接,并且当登录远程桌面后如果不是采用注销方式退出,而是直接关闭远程桌面窗口,那么实际上会话并没有释放掉,而是继续保留在服务器端,这样就会占用总的链接数,当这个数量达到最大允许值时就会出现上面的提示。
解决方案:
法一:用“注销”方式退出远程桌面而不是直接关闭窗口
法二:踢出已经断开连接的用户
1、首先telnet到此主机上(不管你用什么方法),当然如果能直接操作机器更好,不过直接操作就不必用命令行了,用控制台更直观(略过)。
2、Telnet上去后,先看登陆的用户:
输入命令:query user 系统返回:
用户名Username      会话名Session Name      ID   状态State    空闲时间Idle Time     登录时间Logon Time
administrator            console                               0   运行中               .                           2007-1-12 10:24
lucy                                                                           1   唱片            无                            2007-1-12 10:35
>administrator         rdp-tcp#35                      2   已断开               .                          2007-1-25 18:09
此时可以看出的可能跟我的不一样,根据你的具体情况而定。
ID 0 的用户是本地登陆的
ID 1 和 ID 2是3389登陆的用户,前者在运行中, 后者已经断开了,但是断开了仍然占用系统资源和通道,我们要把它踢掉,如下进行操作即可。
输入命令:logoff 1
再看看
C:\Documents and Settings\Administrator.AD>query user
用户名Username      会话名Session Name      ID   状态State    空闲时间Idle Time     登录时间Logon Time
administrator          console                                0   运行中               .                          2007-1-12 10:24
>administrator       rdp-tcp#35                       2   已断开               .                          2007-1-25 18:09
3、如果服务器关闭了telnet功能(这是默认的),还可以通过SqlServer的xp_cmdshell扩展存储过程,使用格式:master.dbo.xp_cmdshell ''''命令内容'''',其余可参考第二步。此方式要求有访问xp_cmdshell的权限。
法三(最佳方法-推荐):限制已断开链接的会话存在时间
一般情况下,我们在维护远程服务器时,不可能长时间在线,但是系统默认的却是只要登录就不再断开。因此,我们可以修改这一默认设置,给它指定一个自动断开的时间即可。
可以在Windows 2003 服务器上通过组策略中设置一下来解决问题:单击"开始→运行",输入"gpedit.msc",回车后打开组策略窗口,然后依次定位到"计算机配置→管理模板→Windows 组件→终端服务→会话",然后在右侧窗口中双击"为断开的会话设置时间限制",在打开的窗口中将"结束断开连接的会话"时间设置为5分钟,或者设置为空闲就断开。

在远程服务器上打开“运行”窗口,输入“tscc.msc”连接设置窗口。然后双击“连接”项右侧的“RDP-Tcp”,切换到“会话”标签,选中“替代用户设置”选项,再给“结束已断开的会话”设置一个合适的时间即可。
法四:增加连接数量,即设置可连接的数量多些
默认情况下允许远程终端连接的数量是2个用户,我们可以根据需要适当增加远程连接同时在线的用户数。
单击“开始→运行”,输入“gpedit.msc”打开组策略编辑器窗口,依次定位到“计算机配置→管理模板→Windows 组件→终端服务”,再双击右侧的“限制连接数量”,将其TS允许的最大连接数设置大一些即可。
经过上面两个配置(法三&法四),基本上就可以保证远程终端连接时不再受限。但仍有人反映,当前同时只有一个用户进行连接,却提示超出最大允许链接数,这又是什么原因呢?出现这种情况是因为操作不当所造成的。在上一个帐户登录远程桌面后退出时,没有采用注销的方式,而是直接关闭远程桌面窗口,那么导致该会话并没有被释放,而是继续保留在服务器端,占用了连接数,这样就会影响下一个用户的正常登录了。
法五:限制用户会话数
对Terminal Services进行限制,使得一个用户仅仅能够连接一次
对于Windows Server 2003,请在Terminal Services Configuration(Terminal Services配置)中将“限制每位用户只有拥有一个会话”(Restrict each user to one session)设置为“是”(Yes)。此外,您可以将“限制终端服务用户使用单个远程会话”组策略设置为“启用”。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/62guangye/archive/2010/02/05/5291415.aspx

posted @ 2010-11-01 17:06 junlin 阅读(1384) | 评论 (0)编辑 收藏

介绍:

     getDefinitionByName是flash.utils下面的,属于工具包类。正如函数名称是通过Name来获得该名称所对应的类对象,意思就是说通过一个类的名称能够获取到该类对象,从而通过该类对象声明一个该类的实例对象。注意该函数中的参数name=类路径+类名称。

 

实例:

     var btncls:Class = getDefinitionByName("mx.controls.Button") as Class ;

     var myBtn:Object = new btncls() ;

     myBtn.label = "我是通过名字获得类实例声明出来的BTN" ;

      this.addChild( myBtn as DisplayObject ) ;

 

应用:

     现在在flex里面要用到在flash cs3 设计一批元件,当然可以通过导出元件的swc然后添加到工程下面的libs下,当需要在flex里面把这些若干元件当成库来获取库中的单个元素时,我们就可以通过geDefinitionByName函数来实现,具体实现步骤为下:

     第一:在flash cs3中准备好若干个元件,并为元件添加链接名称(最好链接名称和元件名称一样)。然后在场景的第一帧里面添加代码如下:

      function getClassByName(cname:String):Class  //cname即为元件的链接名称。
      {
         var mc:Class =  getDefinitionByName(cname) as Class;
         return mc;
      }

      然后生成swf。

      第二:将swf文件放入工程中,用loader将swf文件导入到程序中。在loader导入成功(触发Event.Complete事件)后,loader.content即为swf。然后访问对象的getClassByName()来获取swf中的元件。存入库中,以备后用。

      代码如下:

      var nameArr:Array = ["烛光","菊花"] ;

      var mcArr:Array = new Array() ;

      function init():void

      {

            var loader:Loader = new Loader() ;

            loader.contentLoaderInfo.addEventLinstener( Event.COMPLETE , onComplete  ) ;

            loader.load(new URLRequest("assets/firelib.swf")) ;

       }

       function onComplete(evnet:Event):void

       {

          for(var i:uint=0 ; i<nameArr.length ; i++)

          {

             var cls:Class = Object( event.target.content).getClassByName(nameArr[i]) ;//getClassByName()即为swf场景中定义的函数。

             mcArr.push( { name:nameArr[i] , content:new cls() } ) ;

           }

       }

 

延伸:

     getQualifiedClassName(value:*)String

          根据一个对象返回该对象的包含完全限定类名称的字符串。

      getQualifiedSuperClassName(value:*)String

          根据一个对象返回该对象的基类的完全限定类名的字符串。

      在通过上面两个方法得到一个完全限定类名称之后,运用 getDefinitionByName()就可以将类名转换成类应用。

posted @ 2010-09-09 19:16 junlin 阅读(1560) | 评论 (1)编辑 收藏
flexendpoint的作用是什么?

endpoint

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://127.0.0.1/flexweb/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint" />
    
        </channel-definition>

        <channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
            <endpoint url="https://127.0.0.1/flexweb/messagebroker/amfsecure " class="flex.messaging.endpoints.SecureAMFEndpoint"/>
            <properties>
                <add-no-cache-headers>false</add-no-cache-headers>
            </properties>
        </channel-definition>

        <channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://127.0.0.1/flexweb/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
            <properties>
                <polling-enabled>true</polling-enabled>
                <polling-interval-seconds>4</polling-interval-seconds>
            </properties>
        </channel-definition>
  
  
Flex 调用远程或所在web应用的 BlazeDS服务时,必须建立和远端的通道channel,才能正常通信。
1.  通常的方式是 Flex 在编译时就指定远程的端点 Endpoint,service-config.xml 中的Endpoint 配置是 例如:
Xml代码
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"  
说明:server.name:如果是本机的话,那就是127.0.0.1了,如果发布在网上的话,那一定是一个域名了知道有多么的重要了吧。
      server.port:服务器的端口号。
      context.root:是你的项目名称。
  
编译时指定的方式是在加编译参数,例如:

引用
  -services "services-config.xml" -context-root "/flexWeb"       

   services-config.xml 需要放在当前目录下,或者指定BlazeDS所在的配置文件路径。
2. 在 <mx:RemoteObject/> 对象中指定Endpoint参数:
     例如: 
    Xml代码
<mx:RemoteObject id="roOrder" destination="Hello" showBusyCursor="true" endpoint="http://server:8080/flexWeb/messagebroker/amf">
<mx:RemoteObject id="roOrder" destination="Hello" showBusyCursor="true" endpoint="http://server:8080/flexWeb/messagebroker/amf">
 说明:1) 全路径:          endpoint="http://server:8080/flexWeb/messagebroker/amf" >
       2) 基于contextRoot: endpoint="/flexWeb/messagebroker/amf" >
       3) 基于当前路径:   endpoint="messagebroker/amf" >

posted @ 2010-09-06 16:07 junlin 阅读(1025) | 评论 (0)编辑 收藏

Flex和Java 整合有几种方法,最常见的是:

一,Flex,java在一个项目中。

二,Flex,java分别在两个项目中。

第一种,直接在新建Flex项目中选择应用服务器,选择blazeDS即可。

注意要写上输出文件夹url.endpoint="messagebroker/amf" 写上相对路径即可。

第二种,分别新建Flex ,java 项目,blazeds.war项目中的WebConten/Web-Inf替代java项目下的web-inf。在remoting-config.xml下写上:

<destination id="hxh">  
       <properties>  
           <source>com.demo.hxh</source>  
       </properties>  
    </destination>  
并布署为tomcat.

Flex项目中修改endpoint="/hxh/messagebroker/amf",并设置输出文件夹为java ,WebContent下的,输出文件夹url为java项目,如为http://localhost:8400/hxh

或者新建项目如一,在新建项目java把编译目录设为Flex-webcontent-classes下。

一般问题都错在设置上,endpoint是一个注意点。

关于endpoint:

public interface Endpointextends ManageableAn endpoint receives messages from clients and decodes them, then sends them on to a MessageBroker for routing to a service. The endpoint also encodes messages and delivers them to clients. Endpoints are specific to a message format and network transport, and are defined by the named URI path on which they are located.


在 <mx:RemoteObject/> 对象中指定Endpoint参数:

     1) 全路径:          endpoint="http://server:8080/HelloBlazeDS/messagebroker/amf" >
     2) 基于contextRoot: endpoint="/HelloBlazeDS/messagebroker/amf" >
     3) 基于当前路径:   endpoint="messagebroker/amf" >


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bill1315/archive/2010/07/21/5751496.aspx

posted @ 2010-09-06 16:06 junlin 阅读(914) | 评论 (0)编辑 收藏
一、国外站点
1.资源类

Adobe Flex 2 Component Explorer: 官方的,展示了各种组件的用法,入门必看。

CFlex:很好的一个Flex资源站点,包括教程,新闻,资源站点&hellip;&hellip; 只是页面有点杂乱,大家一般看右边那一栏就行了。

FlexBox:一个收集了网上很多开源组件的站点,是进阶学习的好帮手。

FlexLib:也是一个开源Flex组件站点,不过与FlexBox不同的是,这个是原创,而FlexBox只是收集。

Flex Developer Center:Adobe Flex开发者中心,经常会有一些好的教程出现。

Adobe Labs:这个不用我说了吧。

Flex.org:http://www.flex.org/  官方的,基本上应有尽有。

2. Explorers

Flex 2 Style Explorer:用来设计程序样式风格的工具,很好用,现在源代码已经可以下载。

Flex 2 Primitive Explorer:用来调节各种Primitive图形的组件,非官方的,源代码提供下载。

Flex 2 Filter Explorer:用来调节各种滤镜(filter),非官方的,源代码提供下载。

3. Blogs

MXNA:这个不用我说了吧,虽说这不是一个Blog,但是它聚合了所有优秀的Blog,所以把它放在Blog一栏,下面所有的Blog都在这个聚合中。

Alex Uhlmann:http://weblogs.macromedia.com/auhlmann/

Christophe Coenraets:http://coenraets.org/ 特别推荐

Code Slinger:http://blogs.digitalprimates.net/codeSlinger/

Deitte:http://www.deitte.com/

Doug mccune:http://dougmccune.com/blog/ 特别推荐

Flex Doc Team:http://blogs.adobe.com/flexdoc/

Kuwamoto:http://kuwamoto.org/ 特别推荐

Macromedia Consulting:http://weblogs.macromedia.com/mc/

Matt Chotin:http://weblogs.macromedia.com/mchotin/ 特别推荐

Peter Ent:http://weblogs.macromedia.com/pent/ 特别推荐

Quietly Scheming:http://www.quietlyscheming.com/blog/ 特别推荐

ScaleNine Blog:http://www.scalenine.com/blog/index.php 特别推荐

Steven Webster:http://weblogs.macromedia.com/swebster/

EverythingFlex:http://blog.everythingflex.com/ 特别推荐

Alex&rsquo;s Flex Closet:http://blogs.adobe.com/aharui/ 特别推荐

4. 邮件列表

FlexCoders:http://tech.groups.yahoo.com/group/flexcoders/

Flex Components:http://www.adobe.com/go/flexcomponents 非高级开发者最好别加入

上面是两个比较有名的邮件列表,建议大家提问之前先搜索一下邮件存档,一般都能找到答案,找不到再提问。更多邮件列表请看这里:http://flex.org/community/

5.Cairngorm 相关
Cairngorm Documentation Group 这个里面收集了基本上所有关于Cairngorm的资料

二、国内站点
1.论坛

RIACHINA:前身是RIACN,国内最好的Flex论坛之一。我最初知道Flex从这里开始,对这个站挺有感情,饮水思源,把它排第一。

AnyFlex:国内最好的Flex论坛之一,成立的时间比较早,而且论坛FTP中有很多好的资料。

RIADev:Google网上论坛,d.CAT前辈主持的,一般小问题都能解决。

FlexCoders.cn:刚起步的论坛,不过看域名觉得挺有前途,呵呵。

2.Blogs
Dreamer&rsquo;s Blog:翻译了国外Flex Blog上的大量优秀文章,博主自认为是国内中文资料最多的站点之一。

Y.X.Shawn:对Flex研究很深入,自己写一些开源的组件。

d.CAT:高级开发者,台湾的,为数不多的华语高级开发者,他还做过一个类似Caringorm的架构。

Kenshin:很早就开始研究Flex了,自己开发过很多东西。

3.Cairngorm
  没有。不过我翻译过一个关于Cairngorm 小文档,大概30页左右,或许对你有帮助。

友情提示:上面这些站点中,资源类的更新不快,不用天天看;Blog和MXNA值得天天看,当然您也可以关注本站,因为我会把MXNA上的关于Flex的内容整理过来;有问题请先去邮件列表或者论坛中搜索,基本上都能搜索到。

补充:http://bbs.actionscript3.cn/一个国内的专注于Flex与ActionScript3的论坛.

http://blog.chinaunix.net/u/21684/article_67906.html 博客,里面有有很多Flex的教程和实例.

http://www.flexcoders.cn/又是一个专业的Flex中文论坛
posted @ 2010-09-06 13:52 junlin 阅读(519) | 评论 (0)编辑 收藏

//获得屏幕的分辨率

var x:Number=Capabilities.screenResolutionX;

var y:Number=Capabilities.screenResolutionY;

Alert.show("x="+x+"y="+y);

第二种方法

Alert.show(stage.fullScreenWidth+"=="+stage.fullScreenHeight);

 

//获得stage(工作区)的宽、高

Alert.show(stage.stageWidth+"=="+stage.stageHeight);

 

//读取xml文件
private function readxml2():void

{

var urlrequest:URLRequest=new URLRequest("file/stu.xml");

var urlloader:URLLoader=new URLLoader(urlrequest);

urlloader.addEventListener(Event.COMPLETE, completehandler);

}

 

private function completehandler(event:Event):void

{

var xml:XML=new XML(event.target.data);

// var arr:Array=new Array(xml);

this.dg.dataProvider=xml.children();

this.tree.dataProvider=xml;

this.cb.dataProvider=xml.children();

// this.hlist.dataProvider=xml.children();

}


//flex 获得系统路径

var add:String=ExternalInterface.call("window.location.href.toString",1);

Alert.show(add);

 

//背景颜色不断变化

 private function changeBG():void{

var mytime:Timer=new Timer(2000);

mytime.addEventListener(TimerEvent.TIMER,changHandle);

mytime.start();

 }

 private function changHandle(e:TimerEvent):void{

this.setStyle("backgroundColor",Math.random()* 0xffffff);

 }

 

//获得键盘按下的键的值

public function getCode():void

{

btn.addEventListener(KeyboardEvent.KEY_DOWN, keyHandle);

}

 

function keyHandle(event:KeyboardEvent):void

{

Alert.show("你按下了:" + String.fromCharCode(event.charCode));

}

//动态加载不同界面

import commont.Two;

import commont.One;

var t:Two=new Two();

var o:One=new One();

private function showOne():void{

tw.removeAllChildren();

tw.addChild(o);

}

private function showTwo():void{

tw.removeAllChildren();

tw.addChild(t);

}

//flex 绑定图片

[Bindable]

[Embed(source="img/1.jpg")]

public var phone1:Class;

 

//日期中文标题

<mx:DateChooser id="dtchoose" x="219" y="83" dayNames="[日,一,二,三,四,五,六]" monthNames="[一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月]" change="disDate()" minYear="2007"/>

//选择日期 dateChoose

function disDate():void{

txtDate.text=fm.format(dtchoose.selectedDate.toLocaleDateString());

}

 

//flex 中添加html标记

<mx:TextArea id="text" creationComplete="init()" width="248" height="59">

<mx:htmlText>

<![CDATA[

<input type='file'/>

<a href="http://www.baidu.com">你哈!!!</a>

]]>

</mx:htmlText>

</mx:TextArea>

 

//flex 带下划线的链接

this.lblLink.htmlText="<a href='http://www.google.com' target='_blank'>新 闻</a>";
<mx:Label x="524" y="393" text="Hellollll" id="lblLink" rollOver="focusManager.deactivate()" color="blue" opaqueBackground="#ffffff"

 rollOut="focusManager.activate()" styleName="Label"

 creationComplete="link()"/>
.Label{text-roll-over-color:red; text-decoration:underline; background-color:green; font-size:12px; text-selected-color:red;}

 

//flex 转向 URL

Var url:URLRequest=new URLRequest(“http://www.google.cn”);

navigateToURL(url,”_self”);//在本页打开

navigateToURL(url,”_blank”);//在新的一页打开

 

//弹出对话框
---------非模式打开---------

PopUpManager.createPopUp(this,类(界面)的名称);

---------模式打开---------

var ep:Main=new Main ();

PopUpManager.addPopUp(ep,this,true);//界面,打开窗口父类,是否模式

PopUpManager.centerPopUp(ep);//在父类窗口居中

 

//-----Alert的用法

public function test():void

{

var glow:GlowFilter=new GlowFilter();

glow.color=StyleManager.getColorName("blue");//边框颜色

glow.strength=5;

glow.alpha=0.8;

var alert:Alert=Alert.show("是否选择","提示",Alert.YES|Alert.NO,this,alertHandle);

alert.filters=[glow];

}

private function alertHandle(event:CloseEvent):void{

if(event.detail==Alert.YES){

lbl.text="是";

}else{

lbl.text="否";

}

}

 

<mx:Button x="62" y="80" label="Button" click="test()"/>

<mx:Label x="62" y="37" text="Label" width="65" id="lbl"/>

 

//flex Combobox添加 –请选择-

private function loadCB(){

var arr:Array=new Array("-请选择-");

for(var i:int=1;i<10;i++){

arr[i]=i;

}

this.cb.dataProvider=arr;

}

 

 

//combobox 选择的值和下标

private function selected():void{

Alert.show(cb.selectedItem.toString()+"下标:"+cb.selectedIndex);

}

<mx:ComboBox x="194" y="80" id="cb" creationComplete="loadCB()" change="selected()">

 

//鼠标移动变大,Button加图片,变手型

<mx:Button x="72" y="80" label="Button" click="test()" mouseMove="changBig()" mouseOut="changSmall()" id="btn" height="52" icon="@Embed(source='img/3.jpg')"

 labelPlacement="bottom" width="67" useHandCursor="true" buttonMode="true"/>

 

private function changBig():void{

this.btn.scaleX=1.5;

this.btn.scaleY=1.5

}

private function changSmall():void{

this.btn.scaleX=1;

this.btn.scaleY=1;

}

 

//flex panel 拖动效果

<mx:Panel x="194" y="125" width="192" height="121" layout="absolute" id="panel" mouseDown="ondragStart(event)" mouseUp="ondragStop(event)">

</mx:Panel>

private function ondragStart(event:MouseEvent):void{

Panel(event.target).startDrag();

}

private function ondragStop(event:MouseEvent):void{

Panel(event.target).stopDrag();

}

 

//写入共享数据

share=SharedObject.getLocal("username");

share.data.userName=txtUser.text;

share.flush();

 

//读取共享数据

var share:SharedObject=SharedObject.getLocal("username");

Alert.show(share.data.userName);

 

 

 

 

 

 

 

//jsp/html文件嵌入到flex中(需要把flexiframe.swc放在项目的flex_libs下)

 

Application标签内xmlns:code=http://code.google.com/p/flex-iframe/

 

<mx:HDividedBox x="0" y="10" width="100%" height="500">

<mx:Panel width="30%" height="500" layout="absolute">

 

</mx:Panel>

<mx:Panel width="70%" height="500" layout="absolute">

<code:IFrame id="frm" source="file/万年历.html" height="100%" width="100%"/><!-这是最重要的-à

</mx:Panel>

</mx:HDividedBox>

 

//检查使用的操作系统

private function checkOS():void{

var os:String=Capabilities.os;

tt.text="你的操作系统是:--"+os;

}

 

//检查所使用的浏览器

private function checkPlay():void{

var play:String=Capabilities.playerType;

Alert.show(play);

if(play=="ActiveX"){

tt.text="你的浏览器是--IE";

}else if(play=="PlugIn"){

tt.text="你的浏览器是--Mozilla-Firefox";

}else{

tt.text="你的浏览器是--其他";

}

}

 

//检查player的版本和使用的语言

private function other():void{

var v:String=Capabilities.version;

var l:String=Capabilities.language;

tt.text="你的flayer版本号:--"+v+

"\r\n你的语言是:--"+l;

}

 

//改变鼠标样式

[Bindable]

[Embed(source="img/157.jpg")]

public var cur:Class;

private function initCursor(event:Event){

CursorManager.setCursor(cur);

}


//设置AdvancedDataGrid的表头竖线为空

headerSortSeparatorSkin="mx.skins.ProgrammaticSkin"

 

 


//获得鼠标坐标

var cx:Number=CursorManager.currentCursorXOffset;

var cy:Number=CursorManager.currentCursorYOffset;

var id:int=CursorManager.currentCursorID;

Alert.show("x:="+cx+"y:="+y+"id="+id);


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xuhuanchao/archive/2009/10/31/4749241.aspx

posted @ 2010-08-27 09:04 junlin 阅读(587) | 评论 (0)编辑 收藏

Jar包冲突问题是在大型Java软件开发中经常遇到的问题,系统开发人员经常会为解决类似的问题耗费大量的时间进行调试和测试,本文根据各种际情况,结合WebSphere中类加载器,讨论了几种解决jar包冲突问题的办法,并给出了具体实现的步骤及源代码。
读者定位为具有Java和WebSphere开发经验的开发人员。
读者可以学习到在WebSphere中类加载器的定义以及解决jar包冲突问题的几种办法,并可以直接使用文章中提供的Java代码,从而节省他们的开发和调试时间,提高效率。


        大型的基于WebSphere的项目开发中,同一个WebSphereApplicationServer(以下简称WAS)上会部署多个应用程序,而这多个应用程序必然会共用一些jar包,包括第三方提供的工具和项目内部的公共jar等。把这些共用的jar包提取出来在多个应用程序之间共享,不仅可以统一对这些jar包进行维护,同时也提高了WAS的性能。但是随着应用的不断扩大,新的应用程序的不断增加,新的应用程序会希望使用一些更高版本的共享jar包,而由于系统运行维护的需要,老的应用程序仍然希望用老版本的共享jar包,这样就必然造成了共享jar包的版本冲突。jar包版本冲突问题是在大型应用项目的开发中经常遇到的问题,本文试图从WebSphere的类加载器入手,讨论几种在不同情况下解决jar包冲突问题的办法。
WebSphere中类加载器介绍
Jar包冲突实际上是应用程序运行时不能找到真正所需要的类,而影响类的查找和加载的是JVM以及WebSphere中的类加载器(class loader),为此,我们首先介绍一下WebSphere中的类加载器以及一些相关的概念。
WebSphere中类加载器层次结构
Java应用程序运行时,在class执行和被访问之前,它必须通过类加载器加载使之有效,类加载器是JVM代码的一部分,负责在JVM虚拟机中查找和加载所有的Java 类和本地的lib库。类加载器的不同配置影响到应用程序部署到应用程序服务器上运行时的行为。JVM和WebSphere应用程序服务器提供了多种不同的类加载器配置, 形成一个具有父子关系的分层结构。WebSphere中类加载器的层次结构图1所示:

图1:WebSphere中类加载器的层次结构


如上图所示,WebSphere中类加载器被组织成一个自上而下的层次结构,最上层是系统的运行环境JVM,最下层是具体的应用程序,上下层之间形成父子关系。
  • JVM Class loader:位于整个层次结构的最上层,它是整个类加载器层次结构的根,因此它没有父类加载器。这个类加载器负责加载JVM类, JVM 扩展类,以及定义在classpath 环境变量上的所有的Java类。
  • WebSphere Extensions Class loader:WebSphere 扩展类加载器, 它将加载WebSphere的一些runtime 类,资源适配器类等。
  • WebSphere lib/app Class loader:WebSphere服务器类加载器,它将加载WebSphere安装目录下$(WAS_HOME)/lib/app路径上的类。 在WAS v4版本中,WAS使用这个路径在所有的应用程序之间共享jar包。从WAS v5开始, 共享库功能提供了一种更好的方式,因此,这个类加载器主要用于一些原有的系统的兼容。
  • WebSphere "server" Class loader:WebSphere应用服务器类加载器。 它定义在这个服务器上的所有的应用程序之间共享的类。WAS v5中有了共享库的概念之后,可以为应用服务器定义多个与共享库相关联的类加载器,他们按照定义的先后顺序形成父子关系。
  • Application Module Class Loader:应用程序类加载器,位于层次结构的最后一层,用于加载J2EE应用程序。根据应用程序的类加载策略的不同,还可以为Web模块定义自己的类加载器。
关于WebSphere的类加载器的层次结构,以下的几点说明可能更有助于进一步的理解类的查找和加载过程:
  • 每个类加载器负责在自身定义的类路径上进行查找和加载类。
  • 一个子类加载器能够委托它的父类加载器查找和加载类,一个加载类的请求会从子类加载器发送到父类加载器,但是从来不会从父类加载器发送到子类加载器。
  • 一旦一个类被成功加载,JVM 会缓存这个类直至其生命周期结束,并把它和相应的类加载器关联在一起,这意味着不同的类加载器可以加载相同名字的类。
  • 如果一个加载的类依赖于另一个或一些类,那么这些被依赖的类必须存在于这个类的类加载器查找路径上,或者父类加载器查找路径上。
  • 如果一个类加载器以及它所有的父类加载器都无法找到所需的类,系统就会抛出ClassNotFoundExecption异常或者NoClassDefFoundError的错误。
类加载器的委托模式
类加载器有一个重要的属性:委托模式(Delegation Mode,有时也称为加载方式:Classloader mode)。委托模式决定了类加载器在查找一个类的时候, 是先查找类加载器自身指定的类路径还是先查找父类加载器上的类路径。
类加载器的委托模式有两个取值:
  • Parent_First:在加载类的时候,在从类加载器自身的类路径上查找加载类之前,首先尝试在父类加载器的类路径上查找和加载类。
  • Parent_Last:在加载类的时候,首先尝试从自己的类路径上查找加载类,在找不到的情况下,再尝试父类加载器类路径。
有了委托模式的概念,我们可以更加灵活的配置在类加载器的层次结构中类的加载和查找方式。表1中给出了在WebSphere的类加载器层次结构中各个类加载器的委托模式的定义,并给出了不同的类加载器内类的生命周期。


注意:在上表中,"JVM Class loader" 因为在类加载器的最顶层,它没有父类加载器,因此其委托模式为N/A,"WebSphere Extensions Class loader"和"WebSphere lib/app Class loader"的委托模式固定为表中的取值,不可配置,其它的类加载器的委托模式都是可以配置的。
WebSphere中的类加载器策略
WebSphere中对类加载器有一些相关的配置,称为类加载器策略(class loader policy)。类加载器策略指类加载器的独立策略(class loader isolation policy),通过类加载器策略设置,我们可以为WAS和应用程序的类加载器进行独立定义。
每个WAS可以配置自己的应用程序类加载器策略,WAS中的每个应用程序也可以配置自己的Web模块类加载器策略,下面我们对这两种策略分别介绍。
1.应用服务器(WAS)配置:应用程序类加载器策略
应用服务器对应用程序类加载器策略有两种配置:
  • Single:整个应用服务器上的所有应用程序使用同一个类加载器。在这种配置下,每个应用程序不再有自己的类加载器。
  • Multiple:应用服务器上的每个应用程序使用自己的类加载器。
2.应用程序配置:Web模块类加载器策略
应用程序中对Web模块类加载器有两种配置:
  • Application:整个应用程序内的所有的实用程序jar包和Web模块使用同一个类加载器。
  • Module:应用程序内的每个Web模块使用自己的类加载器。应用程序的类加载器仍然存在,负责加载应用程序中Web模块以外的其它类,包括所有的实用程序jar包。
从上面的定义可以看出,不同的类加载器策略的配置下,类加载器的层次结构上的某些类加载器可能不存在。比如在应用程序服务器的应用程序类加载器策略定义为single的情况下,应用程序的类加载器将不存在,同一个应用服务器上的所有应用程序将共用同一个类加载器,这也就意味着不同的应用程序之间的类是共享的,应用程序间不能存在同名的类在WebSphere中解决jar包冲突
Jar包冲突问题实际上就是应用程序希望用某一个确定版本的jar包中的类,但是类加载器却找到并加载了另外一个版本的jar包中的类。在上一部分介绍了WebSphere中类加载器的基本概念和相关配置之后,我们来看如何在WebSphere中解决jar包冲突。
在WAS v5版本之前,使用共享jar包的方式是将jar包放在$(WAS_HOME)/lib/app路径下,从上一部分中,我们可以看到,这个路径正是"WebSphere lib/app Class loader" 类加载器的类查找路径,WebSphere会查找这个路径以取得相应得jar包中的Java类,从而做到在WebSphere ND上的多个应用程序之间共享jar包的目的。但是这样做的一个缺点就是这些共享jar包暴露给WebSphere ND上所有的应用程序,对于那些希望使用jar包其它版本的应用程序,这些jar包也同样存在在了它们的类加载器类路径上,因此,就不可避免的会造成版本的冲突。在WAS v5版本及之后,增加了共享库(shared library)的概念,推荐的在多个应用程序间共享jar包并避免jar包冲突的方式是使用共享库。
具体分析引起jar包冲突的情况,主要有三种:
  • 多个应用程序间jar包冲突:多个应用程序间由于使用了共享jar包的不同版本而造成jar包版本冲突。
  • 应用程序中多个Web模块间jar包冲突:同一个应用程序内部,不同的Web模块间同时使用一个jar包的不同版本而造成jar包版本冲突。
  • 应用程序中同一个Web模块内jar包冲突:同一个应用程序内部,同一个Web模块内,由于需要同时使用同一个jar包的两个版本而造成的jar包冲突
本部分根据这三种jar包冲突的情况,讨论三种解决jar包冲突的办法,并具体讨论三种解决办法的实现步骤和适用情况:
  • 共享库方式解决jar包冲突:主要解决应用程序间的jar包冲突问题
  • 打包到Web模块中解决jar包冲突:主要解决应用程序中多个Web模块间jar包冲突问题
  • 命令行运行方式解决jar包冲突:主要解决应用程序中同一个Web模块内jar包冲突问题
共享库方式解决jar包冲突
在WAS v5中,提供了一种很好的机制,使得jar包只存在于需要这个jar包的应用程序的类加载器的路径上,而其它的应用程序不受它的任何影响,这就是共享库(Shared library)。共享库可以用在应用服务器级别和应用程序级别,使用应用程序级别的共享库,其好处就是在不同的应用程序之间使用共享jar包的不同版本。我们可以为一些通用jar包的每个不同版本定义成不同的共享库,应用程序希望使用哪个版本,就把这个版本的共享库放到应用程序的类加载器的类路径上,这种方式有效的解决了应用程序之间jar包冲突的问题。
下面举例介绍定义和使用共享库的具体方法,本例中,假设存在xerces.jar包版本冲突。
1. 定义共享库
系统管理员可以在WebSphere的Admin console中定义共享库,可以分别在Cell、Node以及server的级别上定义。
  • 步骤一: 进入Admin console,选择Environment > Shared Library > new。如图2所示:



图2:WebSphere Admin Console中进入共享库页面

  • 步骤二: 给出共享库的名字,并指定共享的文件和目录。多个不同的文件/目录之间通过"Enter"键分隔,且不能有路径分隔符,如":"和";"等。如图3所示:

    图3:WebSphere Admin Console中添加共享库
  • 步骤三:点击Apply或者OK之后,就添加了一个名字为Xerces V2.0的共享库。记住添加完成后一定要在admin console保存配置。如图4所示:

    图4:WebSphere Admin Console中共享库列表
  • 2.安装应用程序
    进入Admin console,选择Applications > Install New Application 安装应用程序。请参照IBMWebSphere的Admin console使用手册进行安装新的应用程序,此处不再详细介绍。
    3.将共享库关联到应用程序

    • 步骤一:进入Admin console,选择Applications >Enterpriseapplications ,并选择需要使用共享库的应用程序。注意:因为要改变应用程序的设置,所以如果应用程序已经运行,需要先停掉应用程序。如图5所示:

      图5:WebSphere Admin Console中选择需要配置的应用程序
    • 步骤二: 点击应用程序,进入后,选择Libraries。如图6所示:

      图6:WebSphere Admin Console中选择应用程序库属性
    • 步骤三: 点击Add,为应用程序添加共享库。如图7所示:

      图7:WebSphere Admin Console中应用程序添加库
    • 步骤四: 从下拉列表中选择所需要的共享库,点击OK。如图8所示:

      图8:WebSphere Admin Console中应用程序添加库页面指定所用的共享库

    这样,Xerces V2.0共享库定义的xerces版本就存在于了应用程序类加载器的类加载路径上。注意,在添加完成后要保存服务器的设置。
    4.设置应用程序的类加载器的委托模式为Parent_Last
    为了进一步防止共享库定义的jar包的其它版本已经存在于JVM或者WebSphere的类加载器路径上,还需要设置应用程序的类加载器的委托方式为Parent_Last。

    • 步骤一:进入Admin console,选择Applications > Enterprise applications > ,选择需要配置的应用程序。如图9所示:

      图9:WebSphere Admin Console中选择需要配置的应用程序
    • 步骤二:点击进入应用程序,设置类加载器的委托模式为Parent_Last。注意:在配置完成后,要保存配置,最后启动应用程序。如图10所示:

      图10:WebSphere Admin Console中为应用程序设置类加载器委托模式

    通过上面的配置,即使xerces的其它版本已经存在于系统中,应用程序在运行时,其类加载器也会首先查找并加载指定的共享库中的xerces版本。这样我们就通过使用共享库的方式,解决了jar包版本冲突问题。
    打包到Web模块中解决jar包冲突
    共享库的方式,只是在应用程序的层次上,在多个应用程序之间解决了共享jar包造成的版本冲突问题,如果一个应用程序的内部,其中一个Web模块使用了一个jar包的A版本,而另一个Web模块使用这个jar包的B版本,在这种情况下造成的jar包冲突,共享库的方式是无法解决的,我们可以考虑将其中一个在多个应用程序间共享的jar包版本,比如A版本,定义成共享库,或者放在"WebSphere lib/app Class loader"类加载器路径上供多个应用程序使用,而将B版本的jar包打包到使用它的Web模块中的方式来解决冲突。
    其次,目前很多在线的系统是WAS v4的遗留系统,其上运行的应用程序已经使用了"WebSphere lib/app Class loader"类加载器,将jar包放在$(WAS_HOME)/lib/app目录下进行共享。如果由于其中某个应用程序的升级或者新增加某个应用程序,需要使用某个共享jar包的其它版本,在这种情况下,为了减少对系统的影响,也可以考虑将这个共享jar包的新版本打包到升级(或新增)的应用程序中的方式来解决jar包冲突。
    由于Web模块的WebContent/WEB-INFO/lib目录在应用程序Web模块的类加载器查找路径上,因此,我们可以把jar包放在这个目录下,Web模块的类加载器将自动查找并加载这个jar包中的类。

    • 步骤一:在WSAD IE集成开发环境中,将冲突jar包放在Web模块的WebContent/WEB-INFO/lib目录下。如图11所示:


    • 图11:WSAD IE中为Web模块添加库
    • 步骤二:在Admin console中,将应用程序部署到WebSphere server上之后,进入Applications > Enterprise Applications,选择相应的应用程序,并确认应用程序不在运行状态(参见前面章节中选择应用程序的步骤)。点击进入应用程序,确认应用程序的类加载器的委托模式为Parent_First,应用程序的类加载器策略为Module。如图12所示:

      图12:WebSphere Admin Console中应用程序属性配置页面
    • 步骤三:在同一个页面上,选择 Web Modules,点击进入。如图13所示:

      图13:WebSphere Admin Console中选择应用程序Web模块属性
    • 步骤四:点击相应的包含冲突jar包的Web模块,设置Web模块的类加载器的委托模式为Parent_Last。注意:在设置完成后要保存服务器配置,并启动应用程序。如图14所示:
      图14:WebSphere Admin Console中为Web模块指定类加载器委托模式
    • 将冲突jar包打包到Web模块中,并设置相应Web模块的类加载器的委托模式为Parent_Last,应用程序在运行过程中加载类的时候,这个Web模块的类加载器会首先查找 WebContent/WEB-INFO/lib目录下的jar包进行类的加载;而对于其它的Web模块,由于其类加载器的委托模式仍然为缺省的Parent_First,它们的类加载器仍然首先从应用程序的共享库或者WebSphere的共享路径上加载jar包中的类,从而解决了jar包冲突的问题。
      命令行运行方式解决jar包冲突
      不论是设置共享库,还是将冲突jar包打包到应用程序中,其解决的问题都是在应用程序的一个Web模块中只使用了冲突jar包的一个版本的情况。我们在开发中曾经遇到过这样的情况:应用程序的Web模块中已经使用了1.4版本的xerces.jar,由于Web功能的扩展,在这个模块中又引入一个新的第三方工具,而这个第三方工具需要使用2.0版本的xerces.jar才能正常工作,这种情况下的jar包冲突如何解决呢?
      在前面类加载器的部分已经介绍过,每个应用程序的一个Web模块最多只能有一个类加载器,而Web模块的类加载器中加载的类的生命周期为整个应用程序的运行期,也就是说,Web模块加载器不可能同时加载一个类的两个版本,同时,Web模块的类加载器的委托模式也是在应用程序运行前设置的,在应用程序运行期内无法改变的,因此,上面描述的在一个Web模块中同时使用两个版本的jar包的问题,象前两种方法那样配置运行在一个JVM内的类加载器的设置的方法是无法解决的。
      唯一的解决办法就是在应用程序运行的JVM外,启动另外一个JVM来运行调用冲突jar包的代码,因为两个不同的JVM可以加载各自的类,从而解决jar包冲突问题。
      这种情况下,原来使用jar包的老版本的方式(包括jar包放置路径,共享库设置方式,类加载器的委托模式等)不变,将对jar包新版本的调用通过命令行运行方式实现。具体做法是:将对jar包新版本内功能的调用,封装到一个可以单独运行的类中,在Web模块中以命令行方式运行这个类。同时把这个类以及jar包的新版本放在任意一个was可访问的路径上(比如/usr/WebSphere),在命令行的classpath参数中包含这个路径(比如/usr/WebSphere)。
      下面通过举例说明命令行运行方式的编程过程,在本例中,假设TestEar应用程序的Web模块TestWar中,已经使用了conflict_v1.jar,由于新添功能需要使用conflict_v2.jar中的exampleCall()功能。
      冲突jar包conflict_v2.jar提供的功能:

      代码1:冲突jar包conflict_v2.jar功能
      Package com.ibm.conflict public class ConflictClass{    …….Public static String exampleCall(string param){    String rs;    ……;    Return rs;}……}

      不存在冲突问题时的编码举例:
      如果没有jar包冲突问题,则对这个功能的调用是简单的,只需要将conflict_v2.jar放在应用程序自身或者其父类加载器的查找路径上,然后在Web模块中直接调用即可,如下:

      代码2:不存在冲突时的调用方式
      Public String methodA(String param){   ……   String rs = ConflictClass.exampleCall(param);   ……   Return rs;}

      存在冲突后的命令行运行方式编码举例
      针对jar包冲突问题,我们需要在Web模块中做如下的修改:
      • 步骤一:将冲突jar包放在was可访问的路径上,比如/usr/WebSphere/conflict_v2.jar。
      • 步骤二:将对包含冲突代码的调用封装到一组可单独运行的类中,它们将调用冲突jar包的功能,并将结果以系统输出的方式打印到系统标准输出上。 将这些类封装到一个单独的jar文件中,比如workAroundConflict.jar,并将其放在was可访问的路径上,比如/usr/WebSphere/workAroundConflict.jar。
        Package com.ibm.test;Import com.ibm.ConflictClassublic class WorkAround{Public static void main(String[] args){    String param1=args[0];    String returnStr=ConflictClass.exampleCall ();    System.out.println("<RTStr>"+returnStr+"</RTStr>");    Return;}}


        代码3:将对冲突代码的调用写入一个单独的类WorkAround
      • 步骤三:在Web模块中通过命令行方式调用封装的类,通过classpath指定所有依赖的jar包和类路径。运行封装类,从系统标准输出中取得运行结果。
        Public static String methodA (String param){    ……    String rtStr = "";    String lStr="<RTStr>";    String rStr="<RTStr>";    //put all the dependency jar here    String classPath="/usr/WebSphere/conflict_v2.jar; /usr/WebSphere/workaroundConflict.jar;……";    String className="com.ibm.test.WorkAround";    String cmdLine="java -classpath " +classPath +" " +className + " "+ param;    Try{        Processprocess = Runtime.getRuntime().exec(cmdLine,null);        process.waitFor();        BufferedReader br= new BufferedReader(                  new InputStreamReader(process.getInputStream()));        while ((s = br.readLine())!=null) {            if (null == out)                ut=s;            else                out+=s;}//get result from outif (null != out){    int lIndex = out.lastIndexOf(lStr);    int rIndex = out.lastIndexOf(rStr);    rsStr = out.substring(lIndex+lStr.length, rIndex);}    } catch (Exception e){        e.printStackTrace();}…….return rsStr;}


        代码4:在应用程序中通过命令行方式运行WorkAround
      命令行运行方式通过启动另外一个JVM的方式运行冲突代码,在一个不同的JVM中加载冲突的类,从而解决了jar包冲突问题。
      但是命令行运行方式毕竟不是一个很好的方式,它存在以下的弊端:
      • 命令行运行方式只适用于对冲突jar包的使用只是运行一段代码,或者只要求返回简单的字符串结果的情况。对于复杂的交互,命令行方式无法做到。但是如果在别无他法的情况下,可以适当地划分封装对冲突代码调用的jar包的包含范围,尽量将命令行运行的代码接口简单化。
      • 命令行运行方式因为启动了另外一个JVM来运行,降低了WebSphere的性能。
      因此,命令行方式只适用于一些极为特殊的情况下解决jar包冲突问题。
      结论
      本文对基于WebSphere的大型项目开发中遇到的jar包冲突问题,结合WebSphere中类加载器的概念,给出了三种解决办法以及相应的操作步骤和实现代码,并分析了各种方式所适用的具体情况。
      项目开发过程中的jar包冲突,主要存在以下三种情况:
      • 多个应用程序间的jar包冲突
      • 应用程序内多个Web模块间的jar包冲突
      • 应用程序内同一个Web模块内部jar包冲突
      通过对类加载器的分析我们知道,解决jar包冲突问题的根本在于合理配置类加载器。在深入理解WebSphere中类加载器的层次结构的基础上,我们给出了"共享库解决jar包冲突"以及"打包到Web模块中解决jar包冲突"的办法,通过合理地配置WebSphere中类加载器及其委托模式,可以解决大多数的jar包冲突问题。但是由于这个层次结构中类加载器只配置到Web模块,因此,对于Web模块内部的jar包冲突问题,类加载器的配置是无法解决的,为此我们给出了"命令行运行方式解决jar包冲突"的办法。
      表2中列出了在不同的WAS版本下,三种解决jar包冲突问题的办法所适用的jar包冲突情况。

      表2:Jar包冲突解决办法适用的jar包冲突情况总结

    posted @ 2010-08-19 16:42 junlin 阅读(1355) | 评论 (0)编辑 收藏

    导航

    <2010年8月>
    25262728293031
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    统计

    常用链接

    留言簿

    随笔分类

    随笔档案

    文章档案

    搜索

    最新评论

    阅读排行榜

    评论排行榜