﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-mulinka-文章分类-我的JAVA</title><link>http://www.blogjava.net/mulinka/category/1841.html</link><description>踏实肯干，不可眼高手低</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 13:15:05 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 13:15:05 GMT</pubDate><ttl>60</ttl><item><title>在Java程序中运行外部类文件（转）</title><link>http://www.blogjava.net/mulinka/articles/11427.html</link><dc:creator>魔之卡卡</dc:creator><author>魔之卡卡</author><pubDate>Mon, 29 Aug 2005 05:03:00 GMT</pubDate><guid>http://www.blogjava.net/mulinka/articles/11427.html</guid><wfw:comment>http://www.blogjava.net/mulinka/comments/11427.html</wfw:comment><comments>http://www.blogjava.net/mulinka/articles/11427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mulinka/comments/commentRss/11427.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mulinka/services/trackbacks/11427.html</trackback:ping><description><![CDATA[<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14><B>一、引言</B></TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>无论是用传统的编程语言（C++、VB等）还是Java语言编程，都经常需要在一个运行的程序中执行另外一个独立的外部程序。例如用Java设计一个IDE程序，那么这个IDE程序就必需能够调式、运行其它独立的外部Java程序。况且直接运行已经存在的外部程序来实现本程序的某些特定的功能，也是提高程序开发效率的一种重要手段。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Java2为实现在一个Java程序中运行外部类文件（即Java程序）提供了的两种解决方案，即在同一进程中运行外部类文件和在不同进程中运行外部类文件。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14><B>二、在同一进程中运行外部类文件</B></TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Java规定任何Java应用（application）的入口都是：main()，因此要实现在同一进程中运行外部类文件，只要想办法在程序中直接调用外部类文件的main()方法即可。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Java2中的映象（Reflection）API可以对Java虚拟机中的类、接口、对象等进行映象，通过它能够动态地得到类、接口、对象的各种信息，还能够动态地设置对象的域的值，并可以动态地调用对象中的各种方法。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>因此，我们可以利用Reflection API在运行时（runtime）动态地确定外部类文件的main()方法，然后调用它。例如：</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>假定将被执行的外部类文件（Invoked.java）如下：</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>public class Invoked {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>public static void main(String[] args) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>if (args.length != 2) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Usage: java Invoked name sex ");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.exit(1);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.out.println("Hello, I come from OutClassFile!");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.out.println("my name is "+args[0]);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.out.println("my sex is "+args[1]);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>运行上述类文件的主程序（Invoker.java）一般具有如下形式：</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>import java.lang.reflect.*;</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>public class Invoker {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>public static void main(String[] args) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//args[0]存储被执行的外部类名，本例中args[0]=“Invoked”</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>if (args.length != 1) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Usage: java Invoker ");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.exit(1);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Class[] argTypes = new Class[1]; </TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>argTypes[0] = String[].class;</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>try {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Method mainMethod = Class.forName(args[0]).getDeclaredMethod("main",argTypes);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Object[] argListForInvokedMain = new Object[1];</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//被调用的main()方法的参数个数=1</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>argListForInvokedMain[0] = new String[2];</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//被调用的main()方法的参数是一个长度为2的String数组</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>String argsToinvoked[]={"WangShuangLin","Man"};</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>ArgListForInvokedMain[0]= argsToinvoked;</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//设置传递给被调用的外部类的main()方法的参数</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>mainMethod.invoke(null, argListForInvokedMain);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//inkoke(Object obj, Object[] args)是调用方法；</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//其中obj是方法所在的对象实例; 但因为这里的main()是静态方法，</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//所以无须实例化，填上null即可；</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>//args是传递给该方法的参数。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>catch (ClassNotFoundException ex) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Class"+args[0]+"not found in classpath.");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>catch (NoSuchMethodException ex) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Class "+args[0]+" does not define public static void main(String[])");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>catch (InvocationTargetException ex) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Exception while executing "+args[0]+ ":"+ex.getTargetException());</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>catch (IllegalAccessException ex) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("main(String[]) in class "+args[0] + "is not public");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>用如下的命令行运行主程序：java Invoker Invoked。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>这个例子简单展示了如何在同一进程（process）中执行外部类文件，不仅如此，而且还是在同一线程（thread）中，当然完全可以在不同的线程中来完成。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14><B>三、在不同进程中运行外部类文件</B></TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>要在不同进程中运行外部类文件，只要想办法在程序中直接执行：</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>java 外部类文件 （本例即为：java Invoked）即可。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>幸运的是java.lang.Runtime 类提供了exce()方法来完成对外部可执行程序的调用。注意：在这里exce()方法调用的其实是java解释器这个可执行程序，外部类文件Invoked.class只不过是作为java解释器的参数出现。事实上，exce()方法还可以直接调用其它的可执行文件，而不仅仅是java解释器。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>假定将被执行的外部类文件仍然是上面的Invoked.java；</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>那么运行上述类文件的主程序（InvokerFromSeparateProcess.java）如下：</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>public class InvokerFromSeparateProcess {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>public static void main(String[] args) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>if (args.length != 1) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Usage: java InvokerFromSeparateProcess ");</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.exit(1);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>String name=” WangShuangLin”;</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>String sex=” man”;</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>try {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>Process p = Runtime.getRuntime().exec("java "+args[0]+name+sex);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>catch (java.io.IOException ex) {</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>System.err.println("Problems invoking class "+args[0]+": "+ex);</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>}</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>用如下的命令行运行主程序：java InvokerFromSeparateProcess Invoked。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>你也许会发现并没有看到被调用的外部类文件Invoked.class的输出。问题在于新进程（new porcess）的标准输出流（standard output stream）并不会自动地定向到stdout。为了得到并显示新进程的输出信息，我们可以利用p.getInputStream()来读取新进程的输出信息，然后把读到的信息发送到标准输出流（standard output）上。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14><B>四、结语</B></TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>利用Java2中的映象（Reflection）API实现在同一进程（process）中执行外部类文件的方法，优点是消耗资源较少，因为它不打开新的进程；功能强大，因为它不但可以执行外部类文件的main()方法，而且还可以执行外部类文件的其它方法，可以非常细致地利用外部类文件的一切资源。缺点是它只能执行用Java编写的外部类文件，而不能执行其它形式的可执行文件，如EXE、COM等；其次是编程较第二种形式稍微复杂一点。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>利用java.lang.Runtime 类提供了exce()方法来完成对外部可执行程序的调用的方法，优点是编程简单，并且可以运行一切可执行程序，包括用其它语言编写的程序。缺点是消耗资源较多，因为它要打开新的进程；其次是它只能整体运行外部类文件，而不能细致地访问被调用程序的内部资源。</TD></TR></TBODY></TABLE>
<TABLE width="100%">
<TBODY>
<TR>
<TD class=a14>一般情况下，如果要运行用Java编写的外部类文件，选择第一种方法较为灵活、恰当；如果要运行用其它语言编写的可执行程序，选择第二种方法较为方便、直接，但是一般情况下要尽量避免这样做，否则将降低Java程序的跨平台性，因为这种外部程序一般是平台相关的。</TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/mulinka/aggbug/11427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mulinka/" target="_blank">魔之卡卡</a> 2005-08-29 13:03 <a href="http://www.blogjava.net/mulinka/articles/11427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dynamic proxy（动态代理模式）</title><link>http://www.blogjava.net/mulinka/articles/8724.html</link><dc:creator>魔之卡卡</dc:creator><author>魔之卡卡</author><pubDate>Fri, 29 Jul 2005 03:10:00 GMT</pubDate><guid>http://www.blogjava.net/mulinka/articles/8724.html</guid><wfw:comment>http://www.blogjava.net/mulinka/comments/8724.html</wfw:comment><comments>http://www.blogjava.net/mulinka/articles/8724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mulinka/comments/commentRss/8724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mulinka/services/trackbacks/8724.html</trackback:ping><description><![CDATA[Java&nbsp;1.3引入了名为“动态代理类”（Dynamic&nbsp;Proxy&nbsp;Class）的新特性，利用它可为“已知接口的实现”动态地创建包装器（wrapper）类。<BR><BR>使用动态代理，你创建的包装器类不要求为所有方法都使用显式的包装器，创建的子类也不要求具有严格的出身，两者方法可任选一种你认为最好的。但是，动态代理仍然有一个限制。当你使用动态代理时，要包装/扩展的对象必须实现一个接口，该接口定义了准备在包装器中使用的所有方法。这一限制的宗旨是鼓励良好的设计，而不是为你带来更多的麻烦。根据经验，每个类都至少应该实现一个接口（nonconstant接口）。良好的接口用法不仅使动态代理成为可能，还有利于程序的模块化。<BR><BR>2种写invoke()<BR>注意:必须有return&nbsp;method.invoke(wrapped,&nbsp;args)<BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<TABLE class=ubb_code cellSpacing=0 cellPadding=6 width="95%" align=right border=0>
<TBODY>
<TR>
<TD><B>以下内容为程序代码:</B><BR><BR>&nbsp;public&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;Throwable&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;paramTypes&nbsp;=&nbsp;method.getParameterTypes();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i=0;&nbsp;i&nbsp;&lt;&nbsp;paramTypes.length;&nbsp;i++)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(Tool.class.isAssignableFrom(paramTypes[i]))&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args[i]&nbsp;=&nbsp;Tool.RATCHET;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;method.invoke(wrapped,&nbsp;args);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;public&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;m,&nbsp;Object[]&nbsp;args)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;Throwable&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;result;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("before&nbsp;method&nbsp;"&nbsp;+&nbsp;m.getName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;m.invoke(obj,&nbsp;args);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(InvocationTargetException&nbsp;e)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;e.getTargetException();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;RuntimeException("unexpected&nbsp;invocation&nbsp;exception:&nbsp;"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;e.getMessage());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;finally&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("after&nbsp;method&nbsp;"&nbsp;+&nbsp;m.getName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>运行效果如下：<BR>before&nbsp;method&nbsp;bar<BR>after&nbsp;method&nbsp;bar<BR><BR><BR>dynamic&nbsp;proxy的实战步骤<BR>实际上dynamic&nbsp;proxy只有关键以下几个东西<BR>一、业务接口：一个Interface<BR>二、实现业务接口的类：一个继承Interface的Class<BR>三、自己写一个继承了java.lang.reflect.InvocationHandler的Handler类<BR>四、在这个Handler类中实现invoke（）方法<BR>五、在invoke（）方法中一定要记得写return&nbsp;method.invoke(wrapped,&nbsp;args)<BR>六、要使Handler和自己的业务接口关联还的写下面的代码（一般写在Handler类中）<BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<TABLE class=ubb_code cellSpacing=0 cellPadding=6 width="95%" align=right border=0>
<TBODY>
<TR>
<TD><B>以下内容为程序代码:</B><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Object&nbsp;newInstance(Object&nbsp;obj)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;java.lang.reflect.Proxy.newProxyInstance(obj.getClass()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getClassLoader(),&nbsp;obj.getClass().getInterfaces(),new&nbsp;Handler(obj));<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>这样返回的就是经过代理的对象了（把原对象和Handler绑定到一起）<BR><BR>dynamic&nbsp;proxy的典型应用《使用JAVA中的动态代理实现数据库连接池》<BR><BR>dynamic&nbsp;proxy在JDBC上的应用<BR>IBM文章:<BR><A href="http://www-900.cn.ibm.com/developerWorks/cn/java/l-connpoolproxy/index.shtml" target=_blank>《使用JAVA中的动态代理实现数据库连接池》</A><img src ="http://www.blogjava.net/mulinka/aggbug/8724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mulinka/" target="_blank">魔之卡卡</a> 2005-07-29 11:10 <a href="http://www.blogjava.net/mulinka/articles/8724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中ThreadLocal的设计与使用</title><link>http://www.blogjava.net/mulinka/articles/7377.html</link><dc:creator>魔之卡卡</dc:creator><author>魔之卡卡</author><pubDate>Fri, 08 Jul 2005 08:54:00 GMT</pubDate><guid>http://www.blogjava.net/mulinka/articles/7377.html</guid><wfw:comment>http://www.blogjava.net/mulinka/comments/7377.html</wfw:comment><comments>http://www.blogjava.net/mulinka/articles/7377.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mulinka/comments/commentRss/7377.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mulinka/services/trackbacks/7377.html</trackback:ping><description><![CDATA[<H3 class=storytitle align=center><A title=Java中ThreadLocal的设计与使用 href="http://www.nihaoblog.com/1_2433.html">Java中ThreadLocal的设计与使用</A></H3>
<DIV class=meta align=right>原文出处：<A title=原文出处 href="http://www.huawei.org.cn/news/article_show.asp?id=27413">http://www.huawei.org.cn/news/article_show.asp?id=27413</A><BR></DIV>
<DIV class=content_story_Bottom></DIV>
<DIV class=storycontent id=storycontent>
<P>
<DIV>
<DIV>
<DIV align=center>&nbsp;</DIV>
<DIV>　　早在Java 1.2推出之时，Java平台中就引入了一个新的支持：java.lang.ThreadLocal，给我们在编写多线程程序时提供了一种新的选择。使用这个工具类可以很简洁地编写出优美的多线程程序，虽然ThreadLocal非常有用，但是似乎现在了解它、使用它的朋友还不多。<BR>　　<BR>　　<STRONG>ThreadLocal是什么</STRONG></DIV>
<DIV><BR>　　ThreadLocal是什么呢？其实ThreadLocal并非是一个线程的本地实现版本，它并不是一个Thread，而是thread local variable（线程局部变量）。也许把它命名为ThreadLocalVar更加合适。线程局部变量（ThreadLocal）其实的功用非常简单，就是为每一个使用该变量的线程都提供一个变量值的副本，是每一个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。从线程的角度看，就好像每一个线程都完全拥有该变量。线程局部变量并不是Java的新发明，在其它的一些语言编译器实现（如IBM XL FORTRAN）中，它在语言的层次提供了直接的支持。因为Java中没有提供在语言层次的直接支持，而是提供了一个ThreadLocal的类来提供支持，所以，在Java中编写线程局部变量的代码相对比较笨拙，这也许是线程局部变量没有在Java中得到很好的普及的一个原因吧。<BR>　　<BR>　　<STRONG>ThreadLocal的设计<BR></STRONG>　　<BR>　　首先看看ThreadLocal的接口：<BR>　　<BR>　　Object get() ; // 返回当前线程的线程局部变量副本 protected Object initialValue(); // 返回该线程局部变量的当前线程的初始值<BR>　　void set(Object value); // 设置当前线程的线程局部变量副本的值<BR>　　<BR>　　ThreadLocal有3个方法，其中值得注意的是initialValue()，该方法是一个protected的方法，显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值，这个方法是一个延迟调用方法，在一个线程第1次调用get()或者set(Object)时才执行，并且仅执行1次。ThreadLocal中的确实实现直接返回一个null：<BR>　　<BR>　　</DIV>
<BLOCKQUOTE>protected Object initialValue() { return null; }<BR></BLOCKQUOTE>
<DIV>　　<BR>　　ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。比如下面的示例实现：<BR>　　<BR>　　</DIV>
<BLOCKQUOTE>public class ThreadLocal<BR>　　{<BR>　　private Map values = Collections.synchronizedMap(new HashMap());<BR>　　public Object get()<BR>　　{<BR>　　Thread curThread = Thread.currentThread();<BR>　　Object o = values.get(curThread);<BR>　　if (o == null &amp;&amp; !values.containsKey(curThread))<BR>　　{<BR>　　o = initialValue();<BR>　　values.put(curThread, o);<BR>　　}<BR>　　return o;<BR>　　}<BR>　　<BR>　　public void set(Object newValue)<BR>　　{<BR>　　values.put(Thread.currentThread(), newValue);<BR>　　}<BR>　　<BR>　　public Object initialValue()<BR>　　{<BR>　　return null;<BR>　　}<BR>　　}<BR></BLOCKQUOTE>
<DIV>　　<BR>　　当然，这并不是一个工业强度的实现，但JDK中的ThreadLocal的实现总体思路也类似于此。<BR>　　<BR>　　<STRONG>ThreadLocal的使用<BR></STRONG>　　<BR>　　如果希望线程局部变量初始化其它值，那么需要自己实现ThreadLocal的子类并重写该方法，通常使用一个内部匿名类对ThreadLocal进行子类化，比如下面的例子，SerialNum类为每一个类分配一个序号：<BR>　　<BR>　　</DIV>
<BLOCKQUOTE>public class SerialNum<BR>　　{<BR>　　// The next serial number to be assigned<BR>　　<BR>　　private static int nextSerialNum = 0;<BR>　　private static ThreadLocal serialNum = new ThreadLocal()<BR>　　{<BR>　　protected synchronized Object initialValue()<BR>　　{<BR>　　return new Integer(nextSerialNum++);<BR>　　}<BR>　　};<BR>　　<BR>　　public static int get()<BR>　　{<BR>　　return ((Integer) (serialNum.get())).intValue();<BR>　　}<BR>　　}<BR>　　<BR></BLOCKQUOTE>
<DIV>　　SerialNum类的使用将非常地简单，因为get()方法是static的，所以在需要获取当前线程的序号时，简单地调用：<BR>　　<BR>　</DIV>
<BLOCKQUOTE>　int serial = SerialNum.get();<BR></BLOCKQUOTE>
<DIV>　　<BR>　　即可。<BR>　　<BR>　　在线程是活动的并且ThreadLocal对象是可访问的时，该线程就持有一个到该线程局部变量副本的隐含引用，当该线程运行结束后，该线程拥有的所以线程局部变量的副本都将失效，并等待垃圾收集器收集。<BR>　　<BR>　　ThreadLocal与其它同步机制的比较<BR>　　ThreadLocal和其它同步机制相比有什么优势呢？ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突，在普通的同步机制中，是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的，使用这种同步机制需要很细致地分析在什么时候对变量进行读写，什么时候需要锁定某个对象，什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问，ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本，从而隔离了多个线程的数据，每一个线程都拥有自己的变量副本，从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象，在编写多线程代码时，可以把不安全的整个变量封装进ThreadLocal，或者把该对象的特定于线程的状态封装进ThreadLocal。<BR>　　<BR>　　由于ThreadLocal中可以持有任何类型的对象，所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本（1.5）将模版的引入，新的支持模版参数的ThreadLocal类将从中受益。也可以减少强制类型转换，并将一些错误检查提前到了编译期，将一定程度地简化ThreadLocal的使用。<BR>　　<BR>　　<STRONG>总结<BR></STRONG>　　当然ThreadLocal并不能替代同步机制，两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问，是为了多个线程之间进行通信的有效方式；而ThreadLocal是隔离多个线程的数据共享，从根本上就不在多个线程之间共享资源（变量），这样当然不需要对多个线程进行同步了。所以，如果你需要进行多个线程之间进行通信，则使用同步机制；如果需要隔离多个线程之间的共享冲突，可以使用ThreadLocal，这将极大地简化你的程序，使程序更加易读、简洁。&nbsp; </DIV></DIV></DIV></DIV><img src ="http://www.blogjava.net/mulinka/aggbug/7377.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mulinka/" target="_blank">魔之卡卡</a> 2005-07-08 16:54 <a href="http://www.blogjava.net/mulinka/articles/7377.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>