今天同事遇到一个需求:
在外部以jar包的形式存放若干个插件,其中包含插件的类,以及spring配置文件;jar包不在classpath里
要实现这个需求,需要用到自定义的ClassLoader,并调用一些spring提供的API
首先是jar包的结构:
其中net文件夹下面,放了要从外部加载的目标类
package net.kyfxbl.test;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sayName() {
System.out.println(getName());
}
}
配置文件spring-plugin.xml内容是:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="myUser" class="net.kyfxbl.test.User">
<property name="name" value="kyfxbl" />
</bean>
</beans>
现在目标,就是读取hehe.jar中的spring-plugin.xml文件,然后实例化一个User对象
示例代码如下,要说明的是,代码很简陋,仅供参考。主要是由于本人spring学艺不精,所以API调用那块,肯定不是最佳实践,绝对是可以优化的:
public class Main {
public static void main(String[] args) {
try {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"spring-config.xml");
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
.getAutowireCapableBeanFactory();
String configurationFilePath = "jar:file:/C:/hehe.jar!/spring-plugin.xml";
URL url = new URL(configurationFilePath);
UrlResource urlResource = new UrlResource(url);
XmlBeanFactory xbf = new XmlBeanFactory(urlResource);
String[] beanIds = xbf.getBeanDefinitionNames();
for (String beanId : beanIds) {
BeanDefinition bd = xbf.getMergedBeanDefinition(beanId);
beanFactory.registerBeanDefinition(beanId, bd);
}
// 以下这行设置BeanFactory的ClassLoader,以加载外部类
setBeanClassLoader(beanFactory);
Object pluginBean = applicationContext.getBean("myUser");
tryInvoke(pluginBean);
} catch (Exception exc) {
exc.printStackTrace();
}
}
private static void setBeanClassLoader(
DefaultListableBeanFactory beanFactory)
throws MalformedURLException {
String jarFilePath = "c://hehe.jar";
URL jarUrl = new File(jarFilePath).toURI().toURL();
URL[] urls = new URL[] { jarUrl };
URLClassLoader cl = new URLClassLoader(urls);
beanFactory.setBeanClassLoader(cl);
}
private static void tryInvoke(Object bean) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Class<?> paramTypes[] = new Class[0];
Method method = bean.getClass()
.getDeclaredMethod("sayName", paramTypes);
Object paramValues[] = new Object[0];
method.invoke(bean, paramValues);
}
}
如果注释掉
setBeanClassLoader(beanFactory);
则报异常:
Caused by: java.lang.ClassNotFoundException: net.kyfxbl.test.User
所以关键就是通过setBeanClassLoader()方法,修改beanFactory默认的ClassLoader
原理比较简单:如果不做特殊配置的话,spring将使用默认的ClassLoader(也就是App ClassLoader),那么就不会加载hehe.jar中的类。所以通过自定义URLClassLoader,并将其设置为BeanFactory的BeanClassLoader,就可以将hehe.jar加载进来了。有兴趣的朋友可以自行阅读源码,获得更多细节
附带的,为了证明spring默认的ClassLoader就是App ClassLoader,补充了几行测试代码
// 打印ClassLoader看看
printClassLoader(beanFactory);
// 以下这行设置BeanFactory的ClassLoader,以加载外部类
setBeanClassLoader(beanFactory);
private static void printClassLoader(DefaultListableBeanFactory beanFactory) {
ClassLoader defaultBeanClassLoader = beanFactory.getBeanClassLoader();
System.out.println(defaultBeanClassLoader);
ClassLoader currentClassLoader = Main.class.getClassLoader();
System.out.println(currentClassLoader);
}
运行结果:
sun.misc.Launcher$AppClassLoader@addbf1
sun.misc.Launcher$AppClassLoader@addbf1
- 大小: 63.7 KB
分享到:
相关推荐
自定义classloader的使用
这样,每次调用代理类中的方法,都会先检查实现类的class文件是否是最新的,如果不是则重新加载,达到动态加载实现类class的目的。 关键字: Java实现热加载; Java动态加载class; Java覆盖已加载的class; Java...
java自定义类加载classloader文档,包括代码,以及详细的原理及过程
ClassLoader的API使用和自定义
ClassLoader类加载机制和原理详解
热修复和插件化是目前比较热门的技术,要想更好的掌握它们需要了解ClassLoader,下面这篇文章主要给大家介绍了关于Android中自定义ClassLoader耗时问题追查的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧
3-7Tomcat中自定义类加载器的使用与源码实现(1).mp4
ClassLoader类加载器讲解,理解JAVA类加载机制
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
简单的自定义类加载器问候世界hello word,基于磁盘的ClassLoader
ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的
这篇文章主要讲类加载器在android中如何动态的加载其他工程类的过程,对于类加载器的知识就跳过了。
1. ClassLoader(类加载机制) 3. findLoadedClass (查找JVM已经加载过的类) 4. defineClass (定义一个Java
自定义Java类加载器demo,自定义了一个classLoader,重写了loadClass 和findClass,注意 loadClass打破了双亲委派机制,所有的类都要在自定义的class文件中找到,而findClass遵循了双亲委派机制
自定义 ClassLoader 加载任何类时的类名。 ":myCommand" 命令位于默认 REPL 命令之上。 scala > val hello = " hello " MyClassLoader loads classOf < root>.$line3 <<中略>> MyClassLoader loads classOf ...
类加载器是 Java 语言的一个创新,也是 ...不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和 NoClassDefFoundError等异常。
eclipse工程格式 博文链接:https://aga.iteye.com/blog/200818
下面小编就为大家带来一篇classloader类加载器_基于java类的加载方式详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
classloader 源码,自定义classloader
自定义ClassLoader,控制台输入调试。 运行期间 重新载入指定目录的class文件。可实现对于类的功能函数更新。 用到java 反射,@interface 等技术