Java Spring boot在运行时添加和删除单例
参考下面的链接,我希望我的SpringBoot应用程序在运行时在applicationcontext中替换bean 下面是我的尝试 MainClass.javaJava Spring boot在运行时添加和删除单例,java,spring,spring-boot,applicationcontext,Java,Spring,Spring Boot,Applicationcontext,参考下面的链接,我希望我的SpringBoot应用程序在运行时在applicationcontext中替换bean 下面是我的尝试 MainClass.java @SpringBootApplication public class MainClass { public static void main(String[] args) { SpringApplication.run( MainClass.class, args);
@SpringBootApplication
public class MainClass {
public static void main(String[] args) {
SpringApplication.run(
MainClass.class, args);
new Thread(new MyThread()).run();
}
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext(){
return context;
}
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
public Object getBean(String name){
return context.getBean(name, Object.class);
}
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
public void removeBean(String beanName){
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.removeBeanDefinition(beanName);
}
}
@Configuration
@ComponentScan(value="com.en.*")
public class Config {
@Bean
@Qualifier("myMap")
public MapBean myMap(){
MapBean bean = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("a", "a");
bean.setMp(mp);
return bean;
}
@Bean
ApplicationContextProvider applicationContextProvider(){
return new ApplicationContextProvider();
}
}
import java.util.Map;
public class MapBean {
private Map<String, String> mp;
public Map<String, String> getMp() {
return mp;
}
public void setMp(Map<String, String> mp) {
this.mp = mp;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MapBean [mp=");
builder.append(mp);
builder.append("]");
return builder.toString();
}
}
import java.util.HashMap;
import java.util.Map;
import com.en.model.MapBean;
public class MyThread implements Runnable{
static ApplicationContextProvider appCtxPrvdr = new ApplicationContextProvider();
public void run(){
try {
Thread.sleep(5000);
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean1 = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("b", "b");
bean1.setMp(mp);
appCtxPrvdr.addBean("myMap", bean1);
System.out.println("myMap added to AppCtx");
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean2 = new MapBean();
Map<String, String> map2 = new HashMap<>();
map2.put("c", "c");
bean2.setMp(map2);
appCtxPrvdr.addBean("myMap", bean2);
System.out.println("myMap added to AppCtx");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
} catch (Exception e) {
e.printStackTrace();
}
}
}
ApplicationContextProvider.java
@SpringBootApplication
public class MainClass {
public static void main(String[] args) {
SpringApplication.run(
MainClass.class, args);
new Thread(new MyThread()).run();
}
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext(){
return context;
}
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
public Object getBean(String name){
return context.getBean(name, Object.class);
}
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
public void removeBean(String beanName){
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.removeBeanDefinition(beanName);
}
}
@Configuration
@ComponentScan(value="com.en.*")
public class Config {
@Bean
@Qualifier("myMap")
public MapBean myMap(){
MapBean bean = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("a", "a");
bean.setMp(mp);
return bean;
}
@Bean
ApplicationContextProvider applicationContextProvider(){
return new ApplicationContextProvider();
}
}
import java.util.Map;
public class MapBean {
private Map<String, String> mp;
public Map<String, String> getMp() {
return mp;
}
public void setMp(Map<String, String> mp) {
this.mp = mp;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MapBean [mp=");
builder.append(mp);
builder.append("]");
return builder.toString();
}
}
import java.util.HashMap;
import java.util.Map;
import com.en.model.MapBean;
public class MyThread implements Runnable{
static ApplicationContextProvider appCtxPrvdr = new ApplicationContextProvider();
public void run(){
try {
Thread.sleep(5000);
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean1 = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("b", "b");
bean1.setMp(mp);
appCtxPrvdr.addBean("myMap", bean1);
System.out.println("myMap added to AppCtx");
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean2 = new MapBean();
Map<String, String> map2 = new HashMap<>();
map2.put("c", "c");
bean2.setMp(map2);
appCtxPrvdr.addBean("myMap", bean2);
System.out.println("myMap added to AppCtx");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Config.java
@SpringBootApplication
public class MainClass {
public static void main(String[] args) {
SpringApplication.run(
MainClass.class, args);
new Thread(new MyThread()).run();
}
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext(){
return context;
}
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
public Object getBean(String name){
return context.getBean(name, Object.class);
}
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
public void removeBean(String beanName){
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.removeBeanDefinition(beanName);
}
}
@Configuration
@ComponentScan(value="com.en.*")
public class Config {
@Bean
@Qualifier("myMap")
public MapBean myMap(){
MapBean bean = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("a", "a");
bean.setMp(mp);
return bean;
}
@Bean
ApplicationContextProvider applicationContextProvider(){
return new ApplicationContextProvider();
}
}
import java.util.Map;
public class MapBean {
private Map<String, String> mp;
public Map<String, String> getMp() {
return mp;
}
public void setMp(Map<String, String> mp) {
this.mp = mp;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MapBean [mp=");
builder.append(mp);
builder.append("]");
return builder.toString();
}
}
import java.util.HashMap;
import java.util.Map;
import com.en.model.MapBean;
public class MyThread implements Runnable{
static ApplicationContextProvider appCtxPrvdr = new ApplicationContextProvider();
public void run(){
try {
Thread.sleep(5000);
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean1 = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("b", "b");
bean1.setMp(mp);
appCtxPrvdr.addBean("myMap", bean1);
System.out.println("myMap added to AppCtx");
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean2 = new MapBean();
Map<String, String> map2 = new HashMap<>();
map2.put("c", "c");
bean2.setMp(map2);
appCtxPrvdr.addBean("myMap", bean2);
System.out.println("myMap added to AppCtx");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
} catch (Exception e) {
e.printStackTrace();
}
}
}
因此,根据我下面的理解,事情正在发生
请建议如何多次添加和删除它。在春天,定义和bean是完全不同的事情。删除BeanDefinition后,bean仍存在于ApplicationContext中 因此,我无法真正理解您示例中ApplicationContextProvider的实现 现在,您要求的是非常不寻常的事情,如果您能够提供更多关于为什么在运行时需要这样一个逻辑的信息,那就太好了 我个人认为不应该在应用程序启动时删除bean 有可能或至少是某种“传统”的做法是:
- 在@Conditional annotation(有很多)/@Profile annotation的帮助下,当应用程序上下文启动时,有条件地加载bean
- 在运行时更改bean,为其提供额外的功能,用于此用途
BeanPostProcessor
- 通过定义BeanFactoryPostProcessor改变Bean定义(在极少数情况下使用)
public class MySingleton {
private boolean shouldWork = true;
public void stop() {
shouldWork = false;
}
public void start() {
shouldWork = true;
}
public void doSomething() {
if(shouldWork) {
// do real logic
}
else {
// do nothing, or some minimal thing to not break anything
}
}
}
您的逻辑非常复杂,如果您真的想在运行时用不同的配置刷新bean之类的事情, 请考虑看和 但是,如果您仍然对此不满意,并且需要坚持以上所做的工作,我想问题在于您的方法:
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
因为它没有注册bean定义,所以spring上下文不会知道它确实存在。
建议尝试添加:
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.registerBeanDefinition(beanName,beanDefinition);
所以基本上你的addBean方法应该改变如下
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
BeanDefinition beanDefinition = beanFactory.getBeanDefinition( beanName );
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.registerBeanDefinition(beanName,beanDefinition);
}
既然您链接了Remove和Add bean问题,为什么不使用Add bean one中的一个答案呢?尝试了所有答案,但没有得到最终解决方案。我不知道Conditional&Profile/BeanPostProcessor。我会查一查,然后再打给你。此外,我还需要添加和删除运行时,因为在我的应用程序中,我正在创建套接字对象,并希望在断开连接时重新连接它。重新连接后,我想在APPCTX中存储新的套接字对象。上面的代码只是为了简化我的问题。我使用了BeanPostProcessor。但我不明白如何更改业务逻辑上的bean属性?根据Spring,在bean初始化之前调用postProcessBeforeInitialization,在bean初始化之后调用postProcessAfterInitialization。这些方法调用是自动的。你是在告诉我手动调用postProcessAfterInitialization吗?从第一条注释看,你似乎只需要不创建套接字对象,而是创建一些包含重新连接逻辑的更“复杂”的对象。在这种情况下,您甚至不需要BeanPosProcessor,因为它们在比您的Mark Bramnik更高级的场景中使用:我尝试应用BeanPosProcessor,但它没有反映在应用程序上下文中。我只是在变老。你能帮我一个忙,提供完整的例子吗?我只是觉得你不需要一个bean后处理器。。。见我之前的评论。这还不够好吗?如何在registerBeanDefinition方法调用中创建beanDefinition?编辑了答案,请检查我也尝试过了。但它没有起作用。你能在你的环境中试一试吗?在调用beanFactory.getBeanDefinition(beanName)时,它将抛出异常作为“org.springframework.beans.factory.NoSuchBeanDefinitionException:没有名为“myMap”的bean可用”