为什么在删除bean并添加另一个bean时springboot仅刷新一次bean?

时间:2019-07-05 08:23:13

标签: spring-boot spring-boot-actuator spring-cloud-config

我需要删除相应的Bean,然后添加另一个Bean,但是我发现springboot仅刷新注入的Bean一次

springboot版本是2.1.5.RELEASE,JDK1.8

    public class Users {
        String name;
        int age;
        String gender;

        public Users() {
        }
        public Users(String name, int age, String gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
    }
    @Component
    public class UsersController implements ApplicationRunner {
         @Autowired(required = false)
    //     @Resource
         List<Users> users= Collections.emptyList();


        @Override
        public void run(ApplicationArguments args) {
            System.out.println(users);
        }
    }
    @RestController
    public class HelloController implements 
    BeanDefinitionRegistryPostProcessor, ApplicationContextAware {

        ApplicationContext applicationContext;

        DefaultListableBeanFactory defaultListableBeanFactory;

        Users users;

        int i=0;

        @RequestMapping("/hello1")
        public String index1() {
            return "hello";
        }
        @RequestMapping("/hello3")
        public Users index3() {
            UsersController controller = 
    applicationContext.getBean(UsersController.class);
            controller.run(null);
            return null;
        }

        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry 
    registry) throws BeansException {

        }

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory 
    beanFactory) throws BeansException {
            defaultListableBeanFactory= (DefaultListableBeanFactory) 
    beanFactory;
            Users users=new Users("hello"+(i++),23,"fe");
            this.users=users;
            defaultListableBeanFactory.registerBeanDefinition(users.getName(),
                BeanDefinitionBuilder.genericBeanDefinition(Users.class, () -> 
    users).getRawBeanDefinition());

        }
        @EventListener
        public void onApplicationEvent(@NonNull EnvironmentChangeEvent 
    environmentChangeEvent) {
            System.out.println("before 
    remove:"+applicationContext.getBean(Users.class));
            defaultListableBeanFactory.removeBeanDefinition(users.getName());
            Users users=new Users("hello"+(i++),23,"fe");
            this.users=users;
            defaultListableBeanFactory.registerBeanDefinition(users.getName(),
                    BeanDefinitionBuilder.genericBeanDefinition(Users.class, 
    () -> users).getRawBeanDefinition());

        System.out.println("after:"+applicationContext.getBean(Users.class));
        }

        @Override
        public void setApplicationContext(ApplicationContext 
    applicationContext) throws BeansException {
            this.applicationContext=applicationContext;
        }
    }

pom.xml:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>RELEASE</version>
         </dependency>
         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
             <version>1.18.8</version>
          </dependency>
    </dependencies>

only bootstrap.yml:

     management:
      endpoints:
        web:
          exposure:
           include: '*'
      endpoint:
        health:
          show-details: always

启动应用程序时,它将输出
[Users(name=hello0, age=23, gender=fe)]
然后通过POST访问该网址,
        http://localhost:8080/actuator/refresh
它会输出
        before remove:Users(name=hello0, age=23, gender=fe)
        after:Users(name=hello1, age=23, gender=fe)
然后访问网址
        http://localhost:8080/hello3
输出
        [Users(name=hello1, age=23, gender=fe)]
这是可以预期的,如果再次访问该URL
        http://localhost:8080/actuator/refresh
输出
        before remove:Users(name=hello1, age=23, gender=fe)
        after:Users(name=hello2, age=23, gender=fe)
这也是意料之中的,但请访问url
        http://localhost:8080/hello3
我们希望它输出
        Users(name=hello2, age=23, gender=fe)
但它输出
        Users(name=hello1, age=23, gender=fe)

输出消息不是我们期望的。
如果在UsersController类中将@Autowired更改为@Resource,则应该是正常的。但在实际环境中可能为null,如果使用@Resource
,则应用程序将运行失败 我该如何解决这个问题?
感谢您的宝贵时间。

2 个答案:

答案 0 :(得分:0)

@资源 @懒 可以正确启动应用程序。但这可能会导致错误,例如 ERROR [main] com.Users - No qualifying bean of type 'java.util.List<com.Users>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=), @org.springframework.context.annotation.Lazy(value=true)}

答案 1 :(得分:0)

请查看文档的这一部分,以便在运行时刷新bean:https://cloud.spring.io/spring-cloud-static/Greenwich.SR1/single/spring-cloud.html#refresh-scope