spring:如何用代码动态向容器中添加或移除Bean ?

时间:2022-04-22
本文章向大家介绍spring:如何用代码动态向容器中添加或移除Bean ?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

先来看一张类图:

有一个业务接口IFoo,提供了二个实现类:FooA及FooB,默认情况下,FooA使用@Component由Spring自动装配,如果出于某种原因,在运行时需要将IFoo的实现,则FooA换成FooB,可以用代码动态先将FooA的实例从容器中删除,然后再向容器中注入FooB的实例,代码如下:

1、IFoo接口:

package yjmyzz;

import org.springframework.beans.factory.DisposableBean;

public interface IFoo extends DisposableBean {

    public void foo();
}

2、 FooA实现

package yjmyzz;


import org.springframework.stereotype.Component;

//注:这里的名称fooA,仅仅只是为了后面演示时看得更清楚,非必需
@Component("fooA")
public class FooA implements IFoo {

    public FooA() {
        System.out.println("FooA is created!");
    }

    public void foo() {
        System.out.println("FooA.foo()");
    }

    public void destroy() throws Exception {
        System.out.println("FooA.destroy()");

    }
}

3、FooB实现

package yjmyzz;


public class FooB implements IFoo {

    public FooB() {
        System.out.println("FooB is created!");
    }

    public void foo() {
        System.out.println("FooB.foo()");
    }

    public void destroy() throws Exception {
        System.out.println("FooB.destroy()");
    }
}

4、测试程序AppDemo

package yjmyzz;


import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.AbstractRefreshableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 演示在运行时,动态向容器中添加、移除Bean
 * author:菩提树下的杨过 http://yjmyzz.cnblogs.cm/
 */
public class AppDemo {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

        //从context中取出FooA实例
        IFoo f = ctx.getBean(IFoo.class);
        f.foo();//FooA.foo()

        //输出IFoo的Bean基本信息
        System.out.println(f.getClass());//class yjmyzz.FooA
        String beanName = ctx.getBeanNamesForType(IFoo.class)[0];
        System.out.println(beanName);//fooA
        System.out.println(ctx.isSingleton(beanName));//true


        //销毁FooA实例
        removeBean(ctx, beanName);
        System.out.println(ctx.containsBean(beanName));//false
        System.out.println("------------");

        //注入新Bean
        beanName = "fooB";
        addBean(ctx, beanName, FooB.class);

        //取出新实例
        f = ctx.getBean(beanName, IFoo.class);
        f.foo();

        //输出IFoo的Bean基本信息
        System.out.println(f.getClass());
        beanName = ctx.getBeanNamesForType(IFoo.class)[0];
        System.out.println(beanName);//fooB
        System.out.println(ctx.isSingleton(beanName));//true


        System.out.println("------------");
        showAllBeans(ctx);

        ctx.close();

    }


    /**
     * 向容器中动态添加Bean
     *
     * @param ctx
     * @param beanName
     * @param beanClass
     */
    static void addBean(AbstractRefreshableApplicationContext ctx, String beanName, Class beanClass) {
        BeanDefinitionRegistry beanDefReg = (DefaultListableBeanFactory) ctx.getBeanFactory();
        BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        BeanDefinition beanDef = beanDefBuilder.getBeanDefinition();
        if (!beanDefReg.containsBeanDefinition(beanName)) {
            beanDefReg.registerBeanDefinition(beanName, beanDef);
        }
    }

    /**
     * 从容器中移除Bean
     *
     * @param ctx
     * @param beanName
     */
    static void removeBean(AbstractRefreshableApplicationContext ctx, String beanName) {
        BeanDefinitionRegistry beanDefReg = (DefaultListableBeanFactory) ctx.getBeanFactory();
        beanDefReg.getBeanDefinition(beanName);
        beanDefReg.removeBeanDefinition(beanName);
    }

    /**
     * 遍历输出所有Bean的信息
     */
    static void showAllBeans(AbstractRefreshableApplicationContext ctx) {
        //遍历
        for (String name : ctx.getBeanDefinitionNames()) {
            System.out.println("name:" + name + ",class:" + ctx.getBean(name).getClass());
        }
    }
}

beans.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

       <context:component-scan base-package="yjmyzz" />

</beans>

输出: FooA is created! FooA.foo() class yjmyzz.FooA fooA true FooA.destroy() false ------------ FooB is created! FooB.foo() class yjmyzz.FooB fooB true ------------ name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor,class:class org.springframework.context.annotation.ConfigurationClassPostProcessor name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor,class:class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor name:org.springframework.context.annotation.internalRequiredAnnotationProcessor,class:class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor name:org.springframework.context.annotation.internalCommonAnnotationProcessor,class:class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor name:org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,class:class org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor name:org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor,class:class org.springframework.context.annotation.ConfigurationClassPostProcessor$EnhancedConfigurationBeanPostProcessor name:fooB,class:class yjmyzz.FooB FooB.destroy()