在Spring中按顺序实例化bean?

新手上路,请多包涵

是否可以在 Spring 中设置实例化顺序?

我不想使用 @DependsOn 也不想使用 Ordered 接口。我只需要一个实例化顺序。

@Order 注释的以下用法不起作用:

 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

/**
 * Order does not work here
 */
public class OrderingOfInstantiation {

   public static class MyBean1 {{
      System.out.println(getClass().getSimpleName());
   }}

   public static class MyBean2 {{
      System.out.println(getClass().getSimpleName());
   }}

   @Configuration
   public static class Config {

      @Bean
      @Order(2)
      public MyBean1 bean1() {
         return new MyBean1();
      }

      @Bean
      @Order(1)
      public MyBean2 bean2() {
         return new MyBean2();
      }

   }

   public static void main(String[] args) {
      new AnnotationConfigApplicationContext(Config.class);
   }

}

Bean 仍然按字典顺序实例化。

为什么它在这里不起作用?

无论如何我可以依赖字典顺序吗?

更新

我想要任何允许提供创建顺序的解决方案。

目标是以正确的顺序在配置级别填充集合。 Depends on 与任务不匹配。关于为什么 Spring 不喜欢有序实例化的任何“解释”——也不符合任务。

订单意味着订单:)

原文由 Dims 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 448
2 个回答

来自 @Order javadoc

注意: 仅特定类型的组件 支持基于注释的排序——例如,基于注释的 AspectJ 方面。另一方面,Spring 容器中的排序策略通常基于 Ordered 接口,以便允许以编程方式配置每个实例的排序。

所以我想 Spring 在创建 bean 时并没有遵循 @Order()

但是,如果您只想填充集合,也许这对您来说已经足够了:

 import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.lang.annotation.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Configuration
public class OrderingOfInstantiation {

    public static void main(String[] args) {
        new AnnotationConfigApplicationContext(OrderingOfInstantiation.class);
    }

    @Component
    @CollectionOrder(collection = "myBeans", order = 1)
    public static class MyBean1 {{
        System.out.println(getClass().getSimpleName());
    }}

    @Component
    @CollectionOrder(collection = "myBeans", order = 2)
    public static class MyBean2 {{
        System.out.println(getClass().getSimpleName());
    }}

    @Configuration
    public static class CollectionsConfig {

        @Bean
        List<Object> myBeans() {
            return new ArrayList<>();
        }
    }

    // PopulateConfig will populate all collections beans
    @Configuration
    public static class PopulateConfig implements ApplicationContextAware {

        @SuppressWarnings("unchecked")
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            Multimap<String, Object> beansMap = MultimapBuilder.hashKeys().arrayListValues().build();

            // get all beans
            applicationContext.getBeansWithAnnotation(CollectionOrder.class)
                    .values().stream()

                    // get CollectionOrder annotation
                    .map(bean -> Pair.of(bean, bean.getClass().getAnnotation(CollectionOrder.class)))

                    // sort by order
                    .sorted((p1, p2) -> p1.getRight().order() - p2.getRight().order())

                    // add to multimap
                    .forEach(pair -> beansMap.put(pair.getRight().collection(), pair.getLeft()));

            // and add beans to collections
            beansMap.asMap().entrySet().forEach(entry -> {
                Collection collection = applicationContext.getBean(entry.getKey(), Collection.class);
                collection.addAll(entry.getValue());

                // debug
                System.out.println(entry.getKey() + ":");
                collection.stream()
                        .map(bean -> bean.getClass().getSimpleName())
                        .forEach(System.out::println);
            });
        }

    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    public @interface CollectionOrder {
        int order() default 0;

        String collection();
    }
}

它不会改变实例化顺序,但你会得到有序的集合。

原文由 Yoav Aharoni 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果你想确保一个特定的 bean 在另一个 bean 之前创建,你可以使用 @DependsOn 注释。

 @Configuration
public class Configuration {

   @Bean
   public Foo foo() {
   ...
   }

   @Bean
   @DependsOn("foo")
   public Bar bar() {
   ...
   }
}

请记住,这不会设置顺序,它只保证 bean“foo”在“bar”之前创建。 @DependsOn 的 JavaDoc

原文由 Richard 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题