??xml version="1.0" encoding="utf-8" standalone="yes"?> 下面来看一个例子,在该例子中,我们要完成的工作是利用URLClassLoader加蝲jarq运行其中的cȝ某个Ҏ?/p>
首先我们定义一个接口,使所有承它的类都必d现actionҎQ如下: 完成后将其打包ؓtestInterface.jar文g?/p>
接下来新Z工程Qؓ了编译通过Q引入之前打好的testInterface.jar包。ƈ创徏TestActionc,使它实现ActionInterface接口。如下:
完成后将其打包ؓtest.jarQ放在c盘根目录下。下面要做的是利用URLClassLoader加蝲q运行TestAction的actionҎQƈ返回的值打印在控制C?/p>
新徏一工程Q引入testInterface.jar包。ƈ创徏一可执行类QmainҎQ,在其中加入如下代码: 在上面的例子中,首先利用URLClassLoader加蝲了C:\test.jar包,其中的com.mxjava.TestActionc蝲入内存,其强制转型为testInterface包中的ActionInterfacecdQ最后调用其actionҎQƈ打印到控制台中?/p>
执行E序后,在控制台上如期打印出我们惌的内宏V但是,事情q没有那么简单,当我们将该代码移动web应用中时Q就会抛出异常。原来,Java为我们提供了三种可选择的ClassLoaderQ?br />1. pȝcd载器或叫作应用类加蝲?(system classloader or application classloader) 在上例中我们使用javac命o来运行该E序Q这时候用的是系l类加蝲?(system classloader)。这个类加蝲器处?-classpath下的cd载工作,可以通过ClassLoader.getSystemClassLoader()Ҏ调用?ClassLoader 下所有的 getSystemXXX()的静态方法都是通过q个Ҏ定义的。在代码中,应该量地调用q个ҎQ以其它的类加蝲器作Z理。否则代码将只能工作在简单的命o行应用中。当在web应用中时Q服务器也是利用ClassLoader来加载class的,׃ClassLoader的不同,所以在强制转型时JVM认定不是同一cd。(在JAVA中,一个类用其完全匚wcd(fully qualified class name)作ؓ标识Q这里指的完全匹配类名包括包名和cd。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如果一个名为Pg的包中,有一个名为Cl的类Q被cd载器KlassLoader的一个实例kl1加蝲QCl的实例,即C1.class在JVM中表CZؓ(Cl, Pg, kl1)。这意味着两个cd载器的实?Cl, Pg, kl1) ?(Cl, Pg, kl2)是不同的Q被它们所加蝲的类也因此完全不同,互不兼容的。)Z能够使程序正运行,我们首要解决的问题就是,如何URLClassLoader加蝲的类Q同当前ClassLoader保持在同一cd载器中。解x法很单,利用java提供的第三种ClassLoader—当前线E类加蝲器即可。jdk api文档׃发现QURLClassLoader提供了三U构造方式: 接下来要做的是Q在构造URLClassLoaderӞ当前线E类加蝲器置入即可。如下:
ȝQ?br /> Java是利用ClassLoader来加载类到内存的QClassLoader本n是用java语言写的Q所以我们可以扩展自qClassLoader。利用URLClassLoader可以加蝲指定jar包中的类到内存。在命行上利用URLClassLoader加蝲jarӞ是用系l类加蝲器来加蝲class的,所以在web环境下,׃出错。这是因为JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识的。我们只要利用URLClassLoader的第二种构造方法ƈ传入当前U程cd载器卛_解决?br />
我们知道QJava利用ClassLoader类载入内存Qƈ且在同一应用中,可以有很多个ClassLoaderQ通过委派机制Q把装蝲的Q务传递给上的装载器的,依次cLQ直到启动类装蝲器(没有上c装载器Q。如果启动类装蝲器能够装载这个类Q那么它会首先装载。如果不能,则往下传递。当父类为nullӞJVM内置的类(UCؓ:bootstrap class loader)׃充当父类。想想眼下的来多用XML文g做配|文件或者是描述W、部|符。其实这些通过XML文档描述的配|信息最l都要变成Javac,基实都是通过ClassLoader来完成的。URLClassLoader是ClassLoader的子c,它用于从指向 JAR 文g和目录的 URL 的搜索\径加载类和资源。也是_通过URLClassLoader可以加载指定jar中的class到内存中?/p>
public
interface
ActionInterface
{
public
String action();
}
public
class
TestAction
implements
ActionInterface
{
public
String action()
{
return
"
com.mxjava.TestAction.action
"
;
}
}
URL url
=
new
URL(“file:C:
/
test.jar?;
URLClassLoader myClassLoader
=
new
URLClassLoader(
new
URL[]
{ url }
);
Class myClass
=
myClassLoader.loadClass(“com.mxjava.TestAction?;
ActionInterface action
=
(ActionInterface)myClass.newInstance();
System.out.println(action.action());
2. 当前cd载器
3. 当前U程cd载器
//
使用默认的委托父 ClassLoader 为指定的 URL 构造一个新 URLClassLoader。?/span>
URLClassLoader(URL[] urls)
//
为给定的 URL 构造新 URLClassLoader。?/span>
URLClassLoader(URL[] urls, ClassLoader parent)
//
为指定的 URL、父cd载器和 URLStreamHandlerFactory 创徏斊WURLClassLoader?/span>
URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)
URLClassLoader myClassLoader
=
new
URLClassLoader(
new
URL[]
{ url }
, Thread.currentThread().getContextClassLoader());
参考:
http://www.aygfsteel.com/sharajava/archive/2006/07/25/59946.html
http://kb.csdn.net/java/Articles/200510/a1843d60-05b1-456f-9f72-811cb45ea4ae.html
]]>
也是如我所?抛出java.lang.IllegalAccessException异常Q当时就怀疑Spring框架是否使用反射的一些特性,后来查了相关文档才知道原因何在:
实际上java在反创Z个类的实例时Q默认会是否符合相兛_全,该检开兛_以关闭?br />Constructor、Field、Method都是l承于AccessibleObjectQ对应实例调用setAccessible(true)关闭该开?br />如上面的例子Q在代码 cts[i].newInstance(null);?/font>前调用上q方法: cts[i].setAccessible(true); 呵呵Q这样好像java安全性就大大降低.如果你非常注重应用的安全性,java当然考虑到这斚wQ你可以在JVM启动参数增加 -Djava.security.manager 启用安全理器,如果有该参数,它将正在关闭接入检的代码是否许可了这样做,上述代码执行时会抛出java.security.AccessControlException异常?br />
q样可以创建只有构造函数的实例、调用私有构造方法,讉KcȝU有属性?/p>
外话:
对java 安全性方面了解不多,实际开发中也很与之相养I如哪位同行有相关l验Q请多多指教Q谢谢!
]]>
]]>
]]>