苏州网站制作网络建设公司博州住房和城乡建设部网站
web/
2025/10/6 0:59:33/
文章来源:
苏州网站制作网络建设公司,博州住房和城乡建设部网站,青海旭云网络做网站需要多少钱,重庆建站模板展示我很难思考与Java 加载有关的东西#xff0c;而不是与类加载器有关的东西。 在使用应用程序服务器或OSGi的情况下尤其如此#xff0c;在这些应用程序服务器或OSGi中#xff0c;经常使用多个类加载器#xff0c;并且透明地使用类加载器的能力降低了。 我同意OSGI Alliance B… 我很难思考与Java 加载有关的东西而不是与类加载器有关的东西。 在使用应用程序服务器或OSGi的情况下尤其如此在这些应用程序服务器或OSGi中经常使用多个类加载器并且透明地使用类加载器的能力降低了。 我同意OSGI Alliance Blog文章中关于类加载器的了解 “在模块化环境中类加载器代码会造成严重破坏。” Neil Bartlett在博客文章The Dreaded Thread Context Class Loader上发表了文章他在文章中描述了为什么引入了线程上下文类加载器以及为什么它的使用对OSGi不友好。 Bartlett指出在极少数情况下“一个库只咨询TCCL”但在极少数情况下“我们有些固执”并且“在调用该库之前必须从我们自己的代码中显式设置TCCL。” Alex Miller还写了有关线程上下文类加载器 TCCL的文章并指出“ Java框架没有遵循一致的类加载模式”并且“许多常见且重要的框架的确使用了线程上下文类加载器JMXJAXP JNDI 等等。” 他强调了这一点“如果您使用的是J2EE应用服务器那么几乎可以肯定您依赖于使用线程上下文类加载器的代码。” 在那篇文章中 Miller提供了一种基于动态代理的解决方案以在需要“设置线程上下文类加载器”然后“记住原始上下文类加载器并重新设置”的情况下提供帮助。 Knopflerfish Framework 一种OSGi实现在其文档的“编程”部分中描述了如何使用线程上下文类加载器。 以下引用摘录自Knopflerfish 5.2的“编程”文档的“设置上下文类加载器”部分 像大多数JNDI查找服务一样许多外部库都需要正确设置 线程上下文类加载器 。 如果未设置则即使包含了所有必需的库也可能引发ClassNotFoundException或类似事件。 要解决此问题只需在激活器中生成一个新线程并从该线程中进行工作即可。 … 它是 不建议在启动线程上持久设置上下文类加载器因为该线程对于您的捆绑包而言可能不是唯一的。 效果可能因OSGi供应商而异。 如果您不产生新线程则您 返回之前 必须重置上下文类加载器。 Knopflerish提供了一个简单的类org.knopflerfish.util.ClassLoaderUtil 该类支持切换到提供的类加载器在OSGi应用程序中可能经常是线程上下文类加载器并通过finally子句确保重置了原始上下文类加载器。操作完成后。 我已经实现了该类的我自己的改编该改编在下一个代码清单中显示。 ClassLoaderSwitcher.java package dustin.examples.classloader;/*** Utility class for running operations on an explicitly specified class loader.*/
public class ClassLoaderSwitcher
{/*** Execute the specified action on the provided class loader.** param classLoaderToSwitchTo Class loader from which the* provided action should be executed.* param actionToPerformOnProvidedClassLoader Action to be* performed on the provided class loader.* param T Type of Object returned by specified action method.* return Object returned by the specified action method.*/public static T T executeActionOnSpecifiedClassLoader(final ClassLoader classLoaderToSwitchTo,final ExecutableActionT actionToPerformOnProvidedClassLoader){final ClassLoader originalClassLoader Thread.currentThread().getContextClassLoader();try{Thread.currentThread().setContextClassLoader(classLoaderToSwitchTo);return actionToPerformOnProvidedClassLoader.run();}finally{Thread.currentThread().setContextClassLoader(originalClassLoader);}}/*** Execute the specified action on the provided class loader.** param classLoaderToSwitchTo Class loader from which the* provided action should be executed.* param actionToPerformOnProvidedClassLoader Action to be* performed on the provided class loader.* param T Type of Object returned by specified action method.* return Object returned by the specified action method.* throws Exception Exception that might be thrown by the* specified action.*/public static T T executeActionOnSpecifiedClassLoader(final ClassLoader classLoaderToSwitchTo,final ExecutableExceptionableActionT actionToPerformOnProvidedClassLoader) throws Exception{final ClassLoader originalClassLoader Thread.currentThread().getContextClassLoader();try{Thread.currentThread().setContextClassLoader(classLoaderToSwitchTo);return actionToPerformOnProvidedClassLoader.run();}finally{Thread.currentThread().setContextClassLoader(originalClassLoader);}}
} 在ClassLoaderSwitcher类上定义的两个方法每个都将接口作为其参数之一并带有指定的类加载器。 接口使用run()方法指定一个对象并且将针对提供的类加载器执行run()方法。 接下来的两个代码清单显示接口ExecutableAction和ExecutableExceptionableAction 。 ExecutableAction.java package dustin.examples.classloader;/*** Encapsulates action to be executed.*/
public interface ExecutableActionT
{/*** Execute the operation.** return Optional value returned by this operation;* implementations should document what, if anything,* is returned by implementations of this method.*/T run();
} ExecutableExceptionableAction.java package dustin.examples.classloader;/*** Describes action to be executed that is declared* to throw a checked exception.*/
public interface ExecutableExceptionableActionT
{/*** Execute the operation.** return Optional value returned by this operation;* implementations should document what, if anything,* is returned by implementations of this method.* throws Exception that might be possibly thrown by this* operation.*/T run() throws Exception;
} 调用ClassLoaderSwitcher类上定义的方法的客户端不一定比执行临时上下文类加载器自身切换时要少一些代码但是使用这样的通用类可确保始终更改上下文类加载器返回到原始类加载器从而使开发人员无需确保可以进行重置并防止“重置”在某个时候被无意中删除或在过程中的某个时候移得太晚。 需要为操作临时更改上下文类加载器的客户端可能会这样做如下所示 临时直接将ClassLoader切换为执行动作 final ClassLoader originalClassLoader Thread.currentThread().getContextClassLoader();
try
{Thread.currentThread().setContextClassLoader(BundleActivator.class.getClassLoader());final String returnedClassLoaderString String.valueOf(Thread.currentThread().getContextClassLoader())
}
finally
{Thread.currentThread().setContextClassLoader(originalClassLoader);
} 没有太多的代码行但是必须记住要重置上下文类加载器为其原始类加载器。 接下来演示如何使用ClassLoaderSwitcher实用工具类执行相同的操作。 使用ClassLoaderSwitcher切换类加载器以执行操作JDK 8之前的版本 final String returnedClassLoaderString ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(BundleActivator.class.getClassLoader(),new ExecutableActionString(){Overridepublic String run(){return String.valueOf(Thread.currentThread().getContextClassLoader());}}); 最后一个例子并不比第一个例子短但是开发人员无需担心在第二个例子中显式地重置上下文类加载器。 请注意这两个示例引用BundleActivator来在OSGi应用程序中获取Activator / System类加载器。 这就是我在这里使用的但是可以在此处使用任何在适当的类加载器上加载的类而不是BundleActivator 。 需要注意的另一件事是我的示例使用了一个非常简单的操作该操作在指定的类加载器上执行返回当前线程上下文类加载器的String表示形式在这里效果很好因为它使我很容易看到指定的类加载器是用过的。 在实际情况下此方法可以是在指定的类加载器上运行所需的任何方法。 如果我在指定的类加载器上调用的方法抛出一个已检查的异常则可以使用ClassLoaderSwitcher提供的另一个重载方法同名来运行该方法。 下一个代码清单对此进行了演示。 将ClassLoaderSwitcher与可能引发检查异常的方法一起使用JDK 8之前的版本 String returnedClassLoaderString null;
try
{returnedClassLoaderString ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(BundleActivator.class.getClassLoader(),new ExecutableExceptionableActionString(){Overridepublic String run() throws Exception{return mightThrowException();}});
}
catch (Exception exception)
{System.out.println(Exception thrown while trying to run action.);
} 使用JDK 8我们可以使客户端代码更加简洁。 接下来的两个代码清单包含与前面两个代码清单中显示的方法相对应的方法但已更改为JDK 8样式。 使用ClassLoaderSwitcher切换类加载器以执行动作JDK 8样式 final String returnedClassLoaderString ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(urlClassLoader,(ExecutableActionString) () -{return String.valueOf(Thread.currentThread().getContextClassLoader());}); 将ClassLoaderSwitcher与可能引发检查异常的方法一起使用JDK 8样式 String returnedClassLoaderString null;
try
{returnedClassLoaderString ClassLoaderSwitcher.executeActionOnSpecifiedClassLoader(urlClassLoader,(ExecutableExceptionableActionString) () - {return mightThrowException();});
}
catch (Exception exception)
{System.out.println(Exception thrown while trying to run action.);
} 与直接设置和重置上下文类加载器相比 JDK 8的lambda表达式使使用ClassLoaderSwitcher的客户端代码更加简洁并且可以说更具可读性同时通过确保始终将上下文类加载器切换回其来提供更高的安全性。原始类加载器。 结论 尽管无疑最好避免尽可能多地切换上下文类加载器但是有时您可能没有其他合理的选择。 在那些时候将开关中涉及的多个步骤封装起来然后切换回一个可以由客户端调用的方法可以增加操作的安全性并且如果使用JDK 8编写甚至可以使客户端拥有更简洁的代码。 其他参考 在本文中已经提到了其中一些参考甚至对其进行了重点介绍但为方便起见在此再次将其包括在内。 GitHub上此博客文章中完整类的源代码 不同的包名称 OSGi联盟 关于类加载器的知识 Neil Bartlett 可怕的线程上下文类加载器 纯粹的危险 两个类加载器的故事 信息矿山 OSGi类加载 JNDI教程类加载 AdobeOSGi中的类加载器问题 使用Thread上下文的第三方库 揭秘Java类加载 Knopflerfish 5.2.0文档 编程Knopflerfish设置上下文类加载器 Knopflerfish 5.2.0 Javadoc org.knopflerfish.util.ClassLoaderUtil JavaWorld 从ClassLoader迷宫中寻找出路 技术与达尔文尼亚 Java ClassLoader和Context ClassLoader Impala博客 在多模块环境中使用线程的上下文类加载器 翻译自: https://www.javacodegeeks.com/2016/08/remembering-reset-thread-context-class-loader.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87649.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!