2016-03-23 3 views
1

Возможно ли установить порядок экземпляра в 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); 
    } 

} 

Фасоль по-прежнему конкретизируется в лексикографическом порядке.

Почему это не работает?

Могу ли я полагаться на лексикографический заказ в любом случае?

UPDATE

Я хотел бы любое решение, позволяющее обеспечить порядок создания.

Целью является заполнение коллекций на уровне конфигурации в правильном порядке. Depends on - не соответствует задаче. Любые «объяснения» о том, почему Spring не любит заказывать экземпляры, также не соответствуют задаче.

Ордера заказ :)

+2

Весна определяет порядок в зависимости от зависимостей бобов и '@ DependsOn'. Интерфейс '@ Ordered' или' Ordered' служит совершенно другой цели, так что попытка будет бесполезной. Единственное, что будет работать, это '@ DependsOn'. Но почему порядок важен, как создаются бобы? Единственное, что * может * работать, - это определить каждый компонент в своей «Конфигурации @» и заказать их (но это будет работать только в последних версиях Spring или Spring Boot). –

+0

Причина в том, что я желаю заполнять коллекции на уровне конфигурации. Между созданием компонента с правильно заполненными свойствами нет никакой разницы. Коллекции также должны быть в правильном порядке. Беспорядочное население означает то же самое, что если бы кто-то не мог вводить бобы под правильным названием. – Dims

+3

Вы пытаетесь сделать что-то, что не предназначено для весны. Если вы хотите заполнить коллекцию, тогда заполните коллекцию в том порядке, в котором вы хотите. Создайте бобы, создайте коллекцию, а порядок бобов не имеет значения. Рядом с этой весной можно автоматически заполнить коллекцию со всеми позициями определенного компонента в определенном порядке, если эти бобы упорядочены (тем не менее порядок, в котором они созданы, не имеет значения, они будут упорядочены в конце). Я предлагаю вам поставить образец на то, что вы действительно хотите достичь, поскольку образец, который вы добавили, не то, что вы на самом деле хотите сделать. –

ответ

1

От @Order Javadoc

Примечание: Аннотация на основе упорядочения поддерживается для конкретных видов компонентов только - например, для аннотаций на основе AspectJ аспектов. С другой стороны, стратегии сортировки в контейнере Spring обычно основаны на интерфейсе Ordered, чтобы обеспечить программно конфигурируемое упорядочение каждого экземпляра.

Так что весна просто не следует @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(); 
    } 
} 

Это не изменит порядок создания экземпляра, но вы получите заказанные коллекции.

+0

Извините за всех, но я думаю, что этот ответ наиболее близок к тому, что я думал. – Dims

2

Если вы хотите, чтобы убедиться, что конкретный компонент создается перед другим бобом вы можете использовать @DependsOn аннотацию.

@Configuration 
public class Configuration { 

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

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

Имейте в виду, что это не устанавливает порядок, это гарантирует только то, что боб «Foo» создается до «бар». JavaDoc for @DependsOn

+0

Я хотел бы заказать. – Dims

+0

Работает ли он для всех видов бобов? , я просто пытаюсь работать с компонентом запроса, он не работает должным образом по порядку. –

0

Вы можете наложить упорядочение в вашем примере, сначала устраняя помехи на классах MyBean1 и MyBean2, которые при использовании Spring не нужно почти в каждом случае, как по умолчанию для Spring является экземпляр одного экземпляра каждого боба (аналогично синглтону).

Хитрость заключается в том, чтобы объявить MyBean1 и MyBean2 в @Bean и следить за соблюдением порядка, вы создаете неявное зависимость от bean1 к bean2 путем вызова метода инициализации боб bean2 изнутри метода инициализации bean1 в.

Например:

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 { 

    interface MyBean{ 
     default String printSimpleName(){ 
      System.out.println(getClass().getSimpleName()); 
     } 
    } 

    public class MyBean1 implments MyBean{ 
     public MyBean1(){ pintSimpleName(); } 
    } 

    public class MyBean2 implments MyBean{ 
     public MyBean2(){ pintSimpleName(); } 
    } 

    public class MyBean3 implments MyBean{ 
     public MyBean3(){ pintSimpleName(); } 
    } 

    public class MyBean4 implments MyBean{ 
     public MyBean4(){ pintSimpleName(); } 
    } 

    public class MyBean5 implments MyBean{ 
     public MyBean5(){ pintSimpleName(); } 
    } 

    @Configuration 
    public class Config { 

     @Bean 
     MyBean1 bean1() { 
     //This will cause a a dependency on bean2 
     //forcing it to be created before bean1 
     bean2(); 

     return addToAllBeans(new MyBean1()); 
     } 

     @Bean 
     MyBean2 bean2() { 
     //This will cause a a dependency on bean3 
     //forcing it to be created before bean2 
     bean3(); 

     //Note: This is added just to explain another point 
     //Calling the bean3() method a second time will not create 
     //Another instance of MyBean3. Spring only creates 1 by default 
     //And will instead look up the existing bean2 and return that. 
     bean3(); 

     return addToAllBeans(new MyBean2()); 
     } 

     @Bean 
     MyBean3 bean3(){ return addToAllBeans(new MyBean3()); } 

     @Bean 
     MyBean4 bean4(){ return addToAllBeans(new MyBean4()); } 


     @Bean 
     MyBean5 bean5(){ return addToAllBeans(new MyBean5()); } 


     /** If you want each bean to add itself to the allBeans list **/ 
     @Bean 
     List<MyBean> allBeans(){ 
      return new ArrayList<MyBean>(); 
     } 

     private <T extends MyBean> T addToAllBeans(T aBean){ 
      allBeans().add(aBean); 
      return aBean; 
     } 
    } 

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

Интересный трюк :) Похоже на специальную версию 'DependsOn' ... – Dims

+0

Я обновил ответ, чтобы показать теперь, чтобы вернуть список бобов, сохраняя желаемый порядок. – pczeus

+0

Идея заключалась в том, что каждое определение компонента должно также добавить себя в список, а список должен быть пустым – Dims

Смежные вопросы