`

自定义ClassLoader,让spring加载外部的配置文件和类

阅读更多
今天同事遇到一个需求:

在外部以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
分享到:
评论

相关推荐

    springboot+java类热加载

    例如,`MemoryClassLoader.java`可能就是一个自定义类加载器的实现,它可以在内存中动态加载或更新类。 **JarinJAR**是一种打包技术,它可以将多个JAR文件打包成一个大的JAR文件。在热加载场景下,JarinJAR使得在...

    Java 自动加载JAR文件并运行其中的类方法

    在Java编程中,有时我们需要动态地加载外部JAR文件,并执行其中特定的类方法,这在插件系统、模块化应用或动态扩展性需求中尤为常见。本篇将详细讲解如何实现这一目标。 首先,理解JAR(Java Archive)文件是Java...

    springboot 业务插件demo

    我们可以创建一个自定义的类加载器,用于加载外部的业务插件JAR。自定义类加载器可以优先从特定的目录加载类,而不是默认的系统类路径,这样就能在不重启应用的情况下加载新插件。 4. **Spring Profiles**:Spring ...

    Spring.3.x企业应用开发实战(完整版).part2

    2.2.3 类包及Spring配置文件规划 2.3 持久层 2.3.1 建立领域对象 2.3.2 UserDao 2.3.3 LoginLogDao 2.3.4 在Spring中装配DAO 2.4 业务层 2.4.1 UserService 2.4.2 在Spring中装配Service 2.4.3 单元测试 2.5 展现层 ...

    java文件的加载

    - **用途**:Spring框架提供了强大的依赖注入功能,可以轻松管理配置文件的加载。 - **示例**: ```java import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory....

    Spring3.x企业应用开发实战(完整版) part1

    2.2.3 类包及Spring配置文件规划 2.3 持久层 2.3.1 建立领域对象 2.3.2 UserDao 2.3.3 LoginLogDao 2.3.4 在Spring中装配DAO 2.4 业务层 2.4.1 UserService 2.4.2 在Spring中装配Service 2.4.3 单元测试 2.5 展现层 ...

    springboot参考指南

    改变应用程序外部配置文件的位置 iii. 63.3. 使用'short'命令行参数 iv. 63.4. 使用YAML配置外部属性 v. 63.5. 设置生效的Spring profiles vi. 63.6. 根据环境改变配置 vii. 63.7. 发现外部属性的内置选项 iii. 64....

    java调用插件代码.rar

    默认的类加载器只能加载已知的类路径下的类,但自定义ClassLoader可以加载任何位置的类,包括插件目录。这使得动态加载插件成为可能。 4. **动态代理**: Java的`java.lang.reflect.Proxy`类和`java.lang.reflect....

    20-BAT面试题汇总及详解(进大厂必看).docx

    JVM有多个类加载器,如Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader,它们遵循双亲委派模型,即先由父类加载器尝试加载,失败后再由子类加载器加载。双亲委派模型能避免类的重复加载,保持类的...

    JAVA公共资源模块的设计与开发(源代码+论文).zip

    例如,`BufferedReader`和`FileInputStream`可用于读取文本文件和二进制文件,而`ClassLoader`则能帮助我们在运行时加载类和资源。此外,`java.util.Properties`类是配置文件处理的标准工具,可以用于存储和加载应用...

    高级Java经典面试题2019

    - **应用类加载器**(Application ClassLoader):负责加载用户自定义的类库。 #### GC(Garbage Collection) GC是自动内存管理的过程,用于回收不再使用的对象占用的内存空间。Java的GC机制可以自动检测和清理...

    Drools5.3官网手册

    对于 XStream,则会添加针对 Drools 类的自定义转换器和别名,并负责设置目标 kSession 的 ClassLoader。 - **DroolsEndpoint**:执行指定 Drools 会话中的有效载荷。 Drools 可以像任何常规 Camel 组件一样配置,...

    代码编程 Java 中高级难度 笔试题(附答案)

    - 外部配置文件方便了环境切换。 3. **MyBatis与Hibernate工作原理** - **MyBatis**:半自动化映射框架,需要编写SQL语句。 - **Hibernate**:全自动ORM框架,自动映射实体对象与数据库表。 4. **RESTful API...

    大唐JAVA笔试题

    - Application ClassLoader:加载应用程序类。 #### 9. MVC框架的技术实现及实现方式 - **Model**: - 负责管理应用程序的数据和业务逻辑。 - **View**: - 展示数据,与用户交互。 - **Controller**: - 控制Model...

    程序员成长学习要求

    - **JDK ClassLoader**:理解类加载机制,包括双亲委派模型等,这对于深入理解Java应用的工作原理非常重要。 - **equals与hashCode方法**:了解这两个方法的作用及其实现方式,特别是在自定义类时如何正确重写它们...

    java超有用的面试题目

    - **Classloader**:包括启动类加载器、扩展类加载器、应用类加载器等,采用双亲委派机制。 #### Java内存模型与并发应用 - **指令重排序**:为了优化性能,编译器和处理器可能会重新排列指令执行顺序。 - **内存...

    Java就业面试题264道(独家奉献)

    - 类加载器分为系统类加载器、扩展类加载器和启动类加载器。 - 类加载过程包括加载、连接(验证、准备、解析)、初始化三个阶段。 **23. Servlet的生命周期?** - `init()`: 初始化。 - `service()`: 处理请求。 - ...

    百度2019年最新面试题库

    实现自定义类加载器可以帮助解决特定问题,比如动态加载类、实现安全控制等。 #### 解释一下什么叫AOP(面向切面编程) 面向切面编程(AOP)是一种编程范式,用于分离关注点。通过在不修改类本身的情况下添加新的...

    JAVA核心知识点整理(有效)

    25 3:ServicorTo 和 ServicorFrom 互换................................................................................................................25 2.3.3.1. 2.4.1. 如何确定垃圾 ......................

Global site tag (gtag.js) - Google Analytics