Доступ к Spring bean * not * путем внедрения зависимостей - PullRequest
6 голосов
/ 29 ноября 2009

У нас есть некоторые доменные объекты, которые создаются во время выполнения, а не Spring. Этим доменным объектам нужен доступ к некоторым bean-компонентам типов служб, которыми управляет Spring. Как могут доменные объекты, созданные во время выполнения, динамически обращаться к бинам Spring (не с помощью DI)?

Ответы [ 8 ]

8 голосов
/ 29 ноября 2009

@ ответ duffymo является наиболее распространенным решением этой проблемы, и вам, вероятно, следует следовать.

Однако, если вы чувствуете дерзость и если ваша ситуация это поддерживает, то вы можете рассмотреть возможность использования поддержки AspectJ в Spring для автоматического связывания ваших доменных объектов, не управляемых Spring * с бобами Spring:

[...] содержит аннотации на основе аспект, который использует эту возможность разрешить внедрение зависимостей любого объект. Поддержка предназначена для используется для объектов, созданных вне контроль любого контейнера. Домен объекты часто попадают в эту категорию потому что они часто создаются программно используя новый оператор или с помощью инструмента ORM как результат запроса к базе данных.

Это граничит с вуду, этот материал, и он работает только на определенных серверах приложений, но это может быть инструментом для вас.

7 голосов
/ 29 ноября 2009

Вам нужно будет дать им ссылку на ApplicationContext или BeanFactory, чтобы они могли получить управляемые Spring компоненты.

3 голосов
/ 02 декабря 2009

Создайте Фабрику и зарегистрируйте ее в Spring, используйте фабрику для создания доменного объекта, а не «new»

в этом случае у вас есть все вкусности, доступные для вашего DomainObjFactory

3 голосов
/ 29 ноября 2009

Spring имеет механизм, называемый SingletonBeanFactoryLocator, который можно использовать в местах, таких как приложения EJB 2.0, для получения контекста фабрики / приложения компонента в тех местах, где нельзя использовать внедрение зависимостей. В существующем Spring ContextLoader есть зацепка, которую вы уже используете, чтобы воспользоваться преимуществами этой функции, хотя ее сложно настроить.

Вам нужно будет разделить контексты вашего приложения на отношения родитель / ребенок. Родитель будет содержать объекты сервисного слоя, в то время как дочерний объект состоит из материала, специфичного для веб-слоя.

Затем вам нужно добавить пару параметров контекста в ваш web.xml (как вы делаете это для местоположения конфигурации), чтобы сказать ему инициализировать родителя:

<context-param>
    <param-name>locatorFactorySelector</param-name>
    <param-value>classpath:beanRefFactory.xml</param-value>
</context-param>

<context-param>
    <param-name>parentContextKey</param-name>
    <param-value>beanRefFactory</param-value>
</context-param>

locatorFactorySelector - это ссылка на XML-файл, НО (это то, где я всегда путаюсь), это не будет указывать на XML, который определяет ваши сервисы. Это xml определения бина, который создает бин контекста приложения. Затем вы ссылаетесь на этот компонент с помощью атрибута parentContextKey.

Так, например, beanRefFactory.xml будет содержать:

<beans>
    <bean id="beanRefFactory"
         class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg>
           <list>
                <value>service-context.xml</value>
           </list>
        </constructor-arg>
    </bean>
</beans>

В объектах вашего домена без DIed вы можете получить доступ к контексту приложения с помощью этого кода:

   BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
   BeanFactoryReference contextRef= locator.useBeanFactory(parentContextKey);
   ApplicatonContext context = (ApplicationContext) contextRef.getFactory();

Вы можете найти больше информации о ContextSingletonBeanFactoryLocator в этом блоге . Также есть хорошее описание использования этого подхода в главе о EJB в Разработка Java с Spring Framework .

1 голос
/ 07 декабря 2009

Слегка связанный вопрос

Вы можете принять стратегию, аналогичную Hibernate, создавая средства для перехватчиков на фабрике экземпляров вашего домена. Вы можете внедрить необходимые службы в перехватчики, управляемые пружиной, которые вводятся на фабрики вашего домена

Это отвлечет ваше приложение от определенных интерфейсов Spring. Приведенный ниже пример можно упростить с помощью дженериков, но вы должны понять.

public interface Interceptor {
  public void onCreate(Object entity);
}

public class DomainFactory {
  public void setInterceptors(List<Interceptor> interceptors) { ... }
  public Object createInstance() {
    // iterate interceptors, call onCreate
  }
}

public interface MyServiceAware {
  public void setMyService(MyService service);
}

public class MyServiceInjector implements Interceptor {
  private MyService myService;
  public void onCreate(Object entity) {
    if (entity instanceof MyServiceAware)
      ((MyServiceAware) entity).setMyService(myService);
  }
}

Тогда вы бы настроили что-то вроде

<bean id="myServiceInjector" class="MyServiceInjector">
  <property name="myService" ref="someServiceBean" />
</bean>

<bean class="DomainFactory">
  <property name="interceptors">
    <list>
      <ref bean="myServiceInjector"/>
    </list>
  </property>
</bean>
0 голосов
/ 14 апреля 2010

Вы можете сделать зависимый объект одиночным с помощью статического метода getInstance (), который может использоваться объектами управляемого домена, отличного от Spring. Затем вы сделаете его доступным для Spring через org.springframework.beans.factory.config.MethodInvokingFactoryBean, например:

<bean id="myObject"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod">
        <value>com.example.MyObject.getInstance</value>
    </property>
</bean>
0 голосов
/ 29 ноября 2009

Одним из решений является использование глобального метода static, который возвращает конкурс приложений Spring (см. BeanLocator .)

Другие варианты могут заключаться в том, чтобы ваши бизнес-объекты реализовывали интерфейс ApplicationContextAware. При реализации ваш «интеграционный» код должен был бы внедрить Spring ApplicationContext в динамически создаваемый бин (возможно, проверяя, реализует ли класс ApplicationContextAware.) Это, конечно, связало бы ваш бизнес-код с Spring, но первый вариант было бы то же самое.

Вариантом будет не вводить ApplicationContext напрямую, а повторно использовать аннотацию Spring @Autowired. Затем код «интеграции» вставляет только аннотированные поля.

0 голосов
/ 29 ноября 2009

Вы можете использовать подход, предложенный @duffymo, но в случае, если вы не запускаете Spring в качестве веб-приложения, вам следует посмотреть эту запись SO . Обратите внимание, что в самом популярном ответе служебный класс сделан потокобезопасным. Между прочим, OP и ответ, вы должны получить все, что вам нужно, а затем вы можете использовать этот служебный класс, чтобы получить ссылку на управляемые bean-компоненты Spring.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...