额外JAR包的加载问题

写swiftly的一个场景:需要加载非classpath路径下的jar包。其中用了spring来做容器管理,但是遇到一个问题:无法加载到自己想要的类。

因为是通过:ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path); 来初始化所有的类。

spring默认的classloader会是自己定义的DefaultResourceLoader,并且会把 DefaultResourceLoader设置当前线程的默认加载器。当你在加载外部类的时候就会找不到类,因为加载外部类是在另一个ClassLoader中。先看看几种加载方式

1.加载到classpath中:


private static URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

private static Method addMethod = initAddMethod();

public static void addClassPath() throws FileNotFoundException {

List<URL> urlList = loadAllURL();

if (CollectionUtils.isEmpty(urlList)) {
 return;
 }

for (URL url : urlList) {
 addURL(url);
 }

}

private static List<URL> loadAllURL() throws FileNotFoundException {
 List<URL> urlList = new ArrayList<URL>();
 File baseDir = new File(rootDir);

if (!baseDir.exists()) {
 LOGGER.error("can not find defaultRepositoryPath");
 throw new FileNotFoundException("base file not find ! file:" + rootDir);
 }

findURLs(baseDir, urlList);

return urlList;
 }

private static void addURL(URL file) {
 try {
 addMethod.invoke(classLoader, new Object[] { file });
 } catch (Exception e) {
 }
 }

private static Method initAddMethod() {
 try {
 Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
 add.setAccessible(true);
 return add;
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 }

第二种 通过自定义ClassLoader来解决加载问题

</pre>
public static ClassLoader createClassLoader(ClassLoader parent) throws FileNotFoundException {

StandardClassLoader classLoader = null;

List<URL> urlList = new ArrayList<URL>();
 File baseDir = new File(rootDir);

if (!baseDir.exists()) {
 LOGGER.error("can not find defaultRepositoryPath");
 throw new FileNotFoundException("base file not find ! file:" + rootDir);
 }

findURLs(baseDir, urlList);
 URL[] urls = urlList.toArray(new URL[urlList.size()]);

if (parent == null) {
 classLoader = new StandardClassLoader(urls);
 } else {
 classLoader = new StandardClassLoader(urls, parent);
 }
 return classLoader;

}
<pre>

在单独跑main方法的情况下都可以,通过ClassPathXmlApplicationContext方式来的时候,需要设置下默认的classloader

</pre>
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
 beanFactory.setBeanClassLoader(classLoader);
<pre>

这个问题困扰了我两天时间,主要还是对spring不熟悉导致。

作者: inter12

在这苦短的人生中,追求点自己的简单快乐

发表评论

电子邮件地址不会被公开。 必填项已用*标注