2015-10-09 1 views
0

У меня возникла проблема с аннотацией весны @Order, похоже, я не могу заставить ее работать в моем приложении. Поэтому мне удалось создать тестовый класс, который имитирует то же поведение, которое @Order не оказывает никакого влияния на мои компоненты. Следующий тест не запускается из-за отсутствия боба напечатал javax.sql.Datasource:Запрос на регистрацию и настройку ручной обработки

package com.so; 

import org.springframework.beans.factory.BeanFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.beans.factory.config.ConfigurableBeanFactory; 
import org.springframework.context.annotation.AnnotationConfigApplicationContext; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.Ordered; 
import org.springframework.core.annotation.Order; 
import org.springframework.jdbc.datasource.AbstractDataSource; 
import org.springframework.stereotype.Repository; 
import org.springframework.stereotype.Service; 

import javax.annotation.PostConstruct; 
import javax.sql.DataSource; 
import java.sql.Connection; 
import java.sql.SQLException; 

public class TestSpring { 

    public static void main(String[] args) { 
     Class<?>[] classes = new Class[]{AConf.class, ADAO.class, AService.class, RepoConf.class} ; 
     AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(classes); 
    } 

    @Configuration 
    @Order(Ordered.HIGHEST_PRECEDENCE + 100) 
    public static class AConf { 

     @Autowired 
     AService aService; 

    } 

    @Repository 
    @Order(Ordered.LOWEST_PRECEDENCE) 
    public static class ADAO { 

     @Autowired 
     @Qualifier("myds") 
     DataSource dataSource; 
    } 

    @Service 
    @Order(Ordered.LOWEST_PRECEDENCE) 
    public static class AService { 

     @Autowired 
     ADAO adao; 

     @PostConstruct 
     public void init() { 
     System.out.println("service init"); 
     } 
    } 

// @Component does not have any effect 
    @Configuration 
    @Order(Ordered.HIGHEST_PRECEDENCE) 
    public static class RepoConf { 

     @Autowired 
     BeanFactory beanFactory; 

     @PostConstruct 
     public void init() { 
     ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; 
     configurableBeanFactory.registerSingleton("myds", new AbstractDataSource() { 
      @Override 
      public Connection getConnection() throws SQLException { 
       return null; 
      } 

      @Override 
      public Connection getConnection(String username, String password) throws SQLException { 
       return null; 
      } 
     }); 
     } 
    } 
} 

Ручная регистрация боб имеет риски, как указано здесь: https://stackoverflow.com/a/11751503/1941560, хотя я не могу выяснить, в каких circumtances что @Order аннотаций работ. Для вышеприведенной конфигурации приложения я ожидаю, что порядок выполнения, например; RepoConf, AConf, ADAO, AService.

Странная вещь, чтобы заметить, что, когда я изменил порядок классов компонентов, объявленных (с начала массива с RepoConf):

Class<?>[] classes = new Class[]{RepoConf.class, AConf.class, ADAO.class, AService.class}; 

или изменил мой AConf класс:

@Configuration 
    @Order(Ordered.HIGHEST_PRECEDENCE + 100) 
    public static class AConf { 

     @Autowired 
     RepoConf repoConf; // must be declared before aService 

     @Autowired 
     AService aService; 

    } 

приложение работает, как ожидалось. Может ли кто-нибудь объяснить поведение весеннего контейнера и как я могу использовать аннотации @Order?

springframework версия Я использую 4.2.1.RELEASE

ответ

0

Судя по JavaDoc documentation для @Order аннотацию, я не думаю, что он используется для создания заказа боба:

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

Консультирование Spring Framework documentation, то @Ordered аннотаций, кажется, используются для:

  • Заказа случаев, когда injected into a collection
  • заказа исполнения event listeners
  • упорядочения @Configuration обработки класса, для например, если вы хотите переопределить компонент по имени.

Из документации не похоже, что @Order предназначен для вашего прецедента.

Однако из документации весны мы видим там depends-on, которая предусматривает, что определенные компоненты должны быть созданы до того, как будет определен бит. Он имеет соответствующую аннотацию @DependsOn.

+0

Я попробовал '@ Order' только на конфигурациях' RestConf' и 'AConf', с этим использованием уже должно быть хорошо, но я тоже не работал. Что означает основной символ по имени? – px5x2

+0

Если у вас есть две фасоли с одинаковым именем, один компонент переопределяет другой, например, если у вас есть фасоль с тем же именем в XML-файлах с несколькими контекстами, которые вы можете контролировать с помощью порядка файлов. Весенние бобы также могут быть определены в классах '@ Configuration', а' @ Order' помещает заказ в классы '@ Configuration', поэтому, если у вас несколько классов' @ Configuration', определяющих '@ Bean' с тем же именем, класс '@ Configuration' с наивысшим приоритетом получает создание' @ Bean' с этим именем. '@ Order' определенно кажется неправильным использованием. '@ DependsOn' выглядит лучше. – sh0rug0ru

0

Похоже, что ваша версия Spring Framework просто игнорирует аннотацию @Order в классах конфигурации.Здесь нет ничего удивительного, потому что эту аннотацию следует использовать только для классов, реализующих интерфейс Ordered. Более того, я никогда не мог найти ссылки на него о классах конфигурации в справочной документации Spring Framework.

В любом случае вы идете в terra incognita здесь. Он не описан в официальной документации, поэтому он будет работать или не зависит от деталей реализации. То, что происходит здесь (видеть результаты):

  • AnnotationConfigApplicationContext первые экземпляры классов конфигурации и их бобы в порядке их декларации
  • тогда строит все бобы в порядке их создания экземпляра

Когда вы регистрируете источник данных myds во время сборки в своем классе конфигурации, он регистрируется во времени для автоподключения в других фасонах, когда repoConf построен до любые другие бобы, использующие их. Но это никогда не гарантируется документацией Spring Framework, и будущие версии могут использовать другой подход, не нарушая их контракт. Кроме того, Spring меняет порядок инициализации, позволяя строить зависимости в зависимости от них.

Так что правильный путь здесь, чтобы сказать, что весна ADAO боб зависит от конфигурацииRepoConf. Просто выбросьте все анкеты Order, которые бесполезны здесь, и поместите @DependsOn. You код может быть:

package com.so; 
... 

public class TestSpring { 

    public static void main(String[] args) { 
     Class<?>[] classes = new Class[]{AConf.class, ADAO.class, AService.class, RepoConf.class} ; 
     AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(classes); 
    } 

    @Configuration 
    public static class AConf { 

     @Autowired 
     AService aService; 

    } 

    @DependsOn("repoConf") 
    @Repository 
    public static class ADAO { 

     @Autowired 
     @Qualifier("myds") 
     DataSource dataSource; 
    } 

    @Service 
    public static class AService { 

     @Autowired 
     ADAO adao; 

     @PostConstruct 
     public void init() { 
     System.out.println("service init"); 
     } 
    } 

    @Configuration("repoConf") 
    public static class RepoConf { 

     @Autowired 
     BeanFactory beanFactory; 

     @PostConstruct 
     public void init() { 
     ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; 
     configurableBeanFactory.registerSingleton("myds", new AbstractDataSource() { 
      @Override 
      public Connection getConnection() throws SQLException { 
       return null; 
      } 

      @Override 
      public Connection getConnection(String username, String password) throws SQLException { 
       return null; 
      } 
     }); 
     } 
    } 
} 

@DependsOnrepoConf гарантирует, что будет создан до ADAO создания источника данных, доступных для инъекции зависимостей.

+0

В первой части вашего ответа я обновил версию весенне-летней версии до версии 4.2.1, которая поддерживает '@ Order' на классах' @ Configuration' (а также реализован интерфейс 'Ordered'), это тоже не сработало. Это по-прежнему открытая проблема для меня. Но да, вы совершенно правы в том, как следует рассматривать этот конкретный случай. Я успешно пробовал '@ DependsOn', просто я пытался избежать' @ DependsOn'. Кажется, я не могу перехватить :) – px5x2

+0

@ px5x2 IMHO, ручную регистрацию инъецируемого компонента следует избегать, если это возможно, потому что Spring понадобится специальная процессия для найдите компонент. Если вам это действительно нужно, я бы не стал полагаться на упорядочение конфигурационного класса, потому что Spring может изменить порядок построения бина, когда он обнаруживает зависимости (зависимости, по возможности, создаются перед зависимыми компонентами). Поэтому вы действительно должны использовать явную зависимость (аннотация @ @ DependsOn) в таком случае использования. –

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