Spring动态加载Bean

创建工具类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访问接口即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容