前幾天自己發表的只運行一個實例的文章,感謝Pande的留意,并提出寶貴意見,他推薦的正好是我想找的RSSOwl源碼,以下是我分析RSSOwl如何做到只運行一個實例并且激活的,如有錯誤,請拍磚。
http://sourceforge.krugle.com/kse/files/cvs/cvs.sourceforge.net/rssowl/RSSOwl/src/java/net/sourceforge/rssowl/controller/RSSOwlLoader.java
根據 RSSOwlLoader.java 中的
[code]
private static void startupProcess( String[] args )
{
? ...
? if( !System.getProperties().containsKey( PROPERTY_ALLOW_MULTI_INSTANCES )&&StartupManager.isRSSOwlRunning( feedArgument ) )
? ...
}
[/code]
追蹤到 StartupManager.java 見下:
http://sourceforge.krugle.com/kse/files/cvs/cvs.sourceforge.net/rssowl/RSSOwl/src/java/net/sourceforge/rssowl/controller/thread/StartupManager.java
追蹤到 StartupManager.isRSSOwlRunning( String message ) 用途為建立ServerSocket,監聽本地8794端口
[code]
static ServerSocket applLockSocket;
public static boolean isRSSOwlRunning( String message )
{
? try{ applLockSocket=new ServerSocket( 8794, 50, InetAddress.getByName( "127.0.0.1" ) );? //1987年9月4日出生?
?????? handleSocketUnBound();? //
?????? return false;
???? }
? catch( java.net.BindException e )??? //Another instance already running
?????? {
???????? ...
???????? handleSocketBound( message );? //
???????? return true;
?????? }?
? catch( IOException e )? //Other Error
?????? {
???????? ...
???????? return false;
?????? }
}
[/code]
追蹤到 StartupManager.handleSocketUnBound() 和 StartupManager.handleSocketBound( String message )
[code]
private static void handleSocketBound( String message )
{
? Socket socket;
? try{ socket=new Socket( InetAddress.getByName( "127.0.0.1" ), 8794 );
?????? PrintWriter writer=new PrintWriter( new OutputStreamWriter( socket.getOutputStream() ) );
?????? writer.println( ( message!=null&&message.length()>0 ) ? message : DEFAULT_MESSAGE );
?????? writer.flush();
???? }
? catch( UnknownHostException e )
?????? {
???????? ...
?????? }
? catch( IOException e )
?????? {
???????? ...
?????? }
}
[/code]
[code]
/**
?* Server not yet running. Start it and listen for incoming messages.
?*/
private static void handleSocketUnBound()
{
? listen();? //轉向,為了對稱好看?還是為了兼容?
}
/**
?* Listen for incoming messages.看看接受的連接發送了什么內容
?*/
private static void listen()
{
? //Run the Server inside a Thread
? server=new ExtendedThread()? //extends from Thread
? {
??? public void run()
??? {
????? while( !isStopped()&&!isInterrupted() )
?????????? {
???????????? BufferedReader buffReader=null;
???????????? try{ //Read a single line from the Socket
????????????????? Socket socket=applLockSocket.accept();
????????????????? buffReader=new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
????????????????? final String message=buffReader.readLine();
????????????????? socket.close();
????????????????? //Check the received message
????????????????? if( ( message!=null&&message.length()>0 )&&GUI.display!=null&&!GUI.display.isDisposed() )? //激活某個GUI的代碼在此,我們進去看看
??????????????????? {
????????????????????? GUI.display.asyncExec( new Runnable()
????????????????????? {
??????????????????????? public void run()
??????????????????????? {
????????????????????????? //Restore the RSSOwl Window and handle Message
????????????????????????? if( GUI.isAlive() )
??????????????????????????? {
????????????????????????????? GUI.rssOwlGui.restoreWindow();? //找到了,轉到GUI.java
????????????????????????????? //Handle the message as Link if valid argument
????????????????????????????? if( RSSOwlLoader.isValidArgument( message ) )
??????????????????????????????? {
????????????????????????????????? GUI.rssOwlGui.getEventManager().actionHandleSuppliedLink( message );
??????????????????????????????? }
??????????????????????????? }
??????????????????????? }
????????????????????? } );
??????????????????? }
??????????????? }
???????????? catch( IOException e )
????????????????? {
??????????????????? ...
????????????????? }
???????????? finally{ //關閉流
??????????????????? }
?????????? }
??? }
? };
? server.setDaemon( true );
? server.setName( "Startup Manager Thread" );
? server.start();
}
[/code]
追蹤到 GUI.java 見下:
http://sourceforge.krugle.com/kse/files/cvs/cvs.sourceforge.net/rssowl/RSSOwl/src/java/net/sourceforge/rssowl/controller/GUI.java
追蹤到GUI.restoreWindow()
[code]
/**
?* Restore the application window either from taskbar or the tray.
?*/
public void restoreWindow()
{
? //RSSOwl is minimized to Tray
? if( GlobalSettings.useSystemTray()&&rssOwlSystray!=null&&rssOwlSystray.isMinimizedToTray() )
??? {
????? rssOwlSystray.restoreWindow();
??? }
? else{ //RSSOwl is not active
??????? shell.forceActive();? //就是它了
??????? shell.setMinimized( false );
????? }
}
[/code]
原理如下:
在本地8794端口建立服務監聽,并且一直監聽此端口,試圖接受此端口其它實例(其它程序?)發送的輸入
如果讀到數據(好像沒有判斷數據的合法性,僅僅判斷數據不為空),并且自己不是“激活”狀態,就“激活”自己;
如果建立服務監聽不成功,說明已經有實例(其它程序?)占用此端口了,向此端口發送數據喚醒前一個實例,停幾秒以便前一個實例接受,然后退出。
程序用的是SWT,激活方法用的是shell.forceActive(),but it's not good for core java.
以上分析如有不對,懇請斧正。
?
posted on 2007-09-01 17:03
NeedJava 閱讀(1471)
評論(1) 編輯 收藏 所屬分類:
Java