创建工具类SpringDynamicBeanLoader.java,内容如下:
package org.demo.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.net.URLClassLoader;
@Component
public class SpringDynamicBeanLoader {
@Autowired
private ConfigurableApplicationContext applicationContext;
/**
* 获取Bean
* @param beanName
* @param clazz
* @return
* @param <T>
*/
public <T>T getBean(String beanName,Class<T> clazz){
return applicationContext.getBean(beanName,clazz);
}
/**
* 动态注册 Bean
* @param beanName Bean 的名称(唯一)
* @param beanClass 动态 Bean 的类
* @param properties Bean 的属性(键值对)
* @param <T> Bean 类型
* @return 注册后的 Bean 实例
*/
@SuppressWarnings("unchecked")
public <T> T registerBean(String beanName, Class<T> beanClass, Object... properties) {
// 步骤 1:获取 BeanDefinitionRegistry(Spring 容器的注册中心)
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
// 步骤 2:构建 BeanDefinition(使用 Builder 简化配置)
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
// 设置属性(示例:传入 properties 为 "name", "动态Bean1")
for (int i = 0; i < properties.length; i += 2) {
String propName = (String) properties[i];
Object propValue = properties[i + 1];
builder.addPropertyValue(propName, propValue);
}
// 可选:设置作用域(默认 singleton,可改为 prototype)
builder.setScope(BeanDefinition.SCOPE_SINGLETON);
BeanDefinition beanDefinition = builder.getBeanDefinition();
// 步骤 3:注册 BeanDefinition 到容器(若已存在则覆盖)
if (registry.containsBeanDefinition(beanName)) {
registry.removeBeanDefinition(beanName);
}
registry.registerBeanDefinition(beanName, beanDefinition);
// 步骤 4:获取并返回 Bean 实例(Spring 会自动初始化)
return applicationContext.getBean(beanName, beanClass);
}
/**
* 加载外部 Jar 中的类并注册为 Bean
* @param jarPath 外部 Jar 的路径(如 "D:/plugins/my-plugin.jar")
* @param className Jar 中的类全限定名(如 "com.plugin.PluginBean")
* @param beanName 注册到 Spring 的 Bean 名称
* @return 动态加载的 Bean 实例
* @throws Exception 类加载异常
*/
public Object loadExternalBean(String jarPath, String className, String beanName) throws Exception {
// 1. 自定义类加载器,加载外部 Jar
URL jarUrl = new URL("file:" + jarPath);
URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}, Thread.currentThread().getContextClassLoader());
// 2. 加载 Jar 中的目标类
Class<?> externalClass = classLoader.loadClass(className);
// 3. 注册为 Spring Bean(复用方案 1 的逻辑)
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(externalClass);
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
// 4. 返回 Bean 实例
return applicationContext.getBean(beanName);
}
/**
* 动态注销 Bean
*/
public void unregisterBean(String beanName) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
if (registry.containsBeanDefinition(beanName)) {
registry.removeBeanDefinition(beanName);
System.out.println("Bean " + beanName + " 已注销");
}
}
}
创建测试的Bean对象,如:
package org.demo.test;
public class TestBean{
public String testLoad() {
return "testLoad方法执行了";
}
}
创建2个测试接口如下:
package org.demo.controller;
import org.demo.test.SpringDynamicBeanLoader;
import org.demo.test.TestBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class Test {
@Autowired
private SpringDynamicBeanLoader springDynamicBeanLoader;
@GetMapping("/a")
public String a() {
springDynamicBeanLoader.getBean("testBean",TestBean.class).testLoad();
return "a";
}
@GetMapping("/load")
public String load() {
springDynamicBeanLoader.registerBean("testBean", TestBean.class);
return "load";
}
}
f访问接口即可。