Получение Spring Application Context - PullRequest
       17

Получение Spring Application Context

203 голосов
/ 24 сентября 2008

Есть ли способ статически / глобально запросить копию ApplicationContext в приложении Spring?

Предполагая, что основной класс запускается и инициализирует контекст приложения, нужно ли передавать его через стек вызовов любым классам, которые в этом нуждаются, или есть ли у класса способ запросить ранее созданный контекст? (Который, я полагаю, должен быть синглтоном?)

Ответы [ 14 ]

166 голосов
/ 25 сентября 2008

Если объект, которому требуется доступ к контейнеру, является компонентом в контейнере, просто реализуйте интерфейсы BeanFactoryAware или ApplicationContextAware .

Если объект вне контейнера нуждается в доступе к контейнеру, я использовал стандартный шаблон синглтона GoF для пружинного контейнера. Таким образом, в вашем приложении только один синглтон, а все остальные - синглтон-бины в контейнере.

113 голосов
/ 14 мая 2012

Вы можете реализовать ApplicationContextAware или просто использовать @Autowired:

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}
В

SpringBean будет введено ApplicationContext, внутри которого создается экземпляр этого компонента. Например, если у вас есть веб-приложение с довольно стандартной иерархией контекстов:

main application context <- (child) MVC context

и SpringBean объявлены в основном контексте, в него будет вставлен основной контекст; в противном случае, если он объявлен в контексте MVC, в него будет вставлен контекст MVC.

38 голосов
/ 24 сентября 2008

Вот хороший способ (не мой, оригинальная ссылка здесь: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

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

Посмотрите на оригинальную ссылку, это очень ясно.

18 голосов
/ 28 сентября 2008

Полагаю, вы могли бы использовать SingletonBeanFactoryLocator . Файл beanRefFactory.xml будет содержать фактический applicationContext, он будет выглядеть примерно так:

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

И код для получения bean-компонента из контекста приложения от Whereever будет выглядеть примерно так:

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");

Команда Spring не одобряет использование этого класса и yadayada, но оно подходит мне там, где я его использовал.

11 голосов
/ 27 сентября 2008

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

  • Почему я пытаюсь получить ApplicationContext?
  • Эффективно ли я использую ApplicationContext в качестве локатора службы?
  • Можно ли вообще избежать доступа к ApplicationContext?

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

Доступ к ApplicationContext нарушает принцип внедрения зависимостей, но иногда у вас нет большого выбора.

6 голосов
/ 30 марта 2009

Если вы используете веб-приложение, существует также другой способ доступа к контексту приложения без использования синглетонов с помощью сервлет-фильтра и ThreadLocal. В фильтре вы можете получить доступ к контексту приложения с помощью WebApplicationContextUtils и сохранить либо контекст приложения, либо необходимые компоненты в TheadLocal.

Внимание: если вы забудете сбросить ThreadLocal, у вас возникнут неприятные проблемы при попытке удалить приложение! Таким образом, вы должны установить его и немедленно начать попытку, которая удаляет ThreadLocal в finally-части.

Конечно, здесь все еще используется одиночный элемент: ThreadLocal. Но настоящие бобы не должны быть больше. Можно даже определить область запроса, и это решение также работает, если у вас есть несколько WAR в приложении с библиотеками в EAR. Тем не менее, вы можете считать это использование ThreadLocal таким же плохим, как и использование простых синглетонов. ; -)

Возможно, Spring уже предлагает подобное решение? Я не нашел ни одного, но точно не знаю.

5 голосов
/ 21 апреля 2017
SpringApplicationContext.java

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Wrapper to always return a reference to the Spring Application 
Context from
 * within non-Spring enabled beans. Unlike Spring MVC's 
WebApplicationContextUtils
 * we do not need a reference to the Servlet context for this. All we need is
 * for this bean to be initialized during application startup.
 */
public class SpringApplicationContext implements 
ApplicationContextAware {

  private static ApplicationContext CONTEXT;

  /**
   * This method is called from within the ApplicationContext once it is 
   * done starting up, it will stick a reference to itself into this bean.
  * @param context a reference to the ApplicationContext.
  */
  public void setApplicationContext(ApplicationContext context) throws BeansException {
    CONTEXT = context;
  }

  /**
   * This is about the same as context.getBean("beanName"), except it has its
   * own static handle to the Spring context, so calling this method statically
   * will give access to the beans by name in the Spring application context.
   * As in the context.getBean("beanName") call, the caller must cast to the
   * appropriate target class. If the bean does not exist, then a Runtime error
   * will be thrown.
   * @param beanName the name of the bean to get.
   * @return an Object reference to the named bean.
   */
  public static Object getBean(String beanName) {
    return CONTEXT.getBean(beanName);
  }
}

Источник: http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html

4 голосов
/ 24 сентября 2008

Взгляните на ContextSingletonBeanFactoryLocator . Он предоставляет статические средства доступа для получения контекста Spring, предполагая, что они были зарегистрированы определенным образом.

Это не красиво и более сложно, чем, возможно, вам бы хотелось, но это работает.

3 голосов
/ 20 февраля 2014

Обратите внимание, что, сохраняя любое состояние из текущего ApplicationContext или самого ApplicationContext в статической переменной - например, с помощью шаблона singleton - вы сделаете ваши тесты нестабильными и непредсказуемыми, если вы используете Spring-test , Это связано с тем, что Spring-test кэширует и повторно использует контексты приложения в той же JVM. Например:

  1. Тест Выполнение, и оно помечено @ContextConfiguration({"classpath:foo.xml"}).
  2. Выполнен тест B и он помечен @ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. Выполнен тестовый С, и он помечен @ContextConfiguration({"classpath:foo.xml"})

При запуске теста A создается ApplicationContext, и любые bean-компоненты, реализующие ApplicationContextAware или автоматическое подключение ApplicationContext, могут записывать в статическую переменную.

Когда выполняется тест B, происходит то же самое, и статическая переменная теперь указывает на тест B ApplicationContext

Когда выполняется тест C, никакие компоненты не создаются , так как TestContext (и в данном документе ApplicationContext) из теста A используется повторно. Теперь вы получили статическую переменную, указывающую на ApplicationContext, отличную от той, которая в данный момент содержит компоненты для вашего теста.

2 голосов
/ 17 октября 2018

Существует множество способов получить контекст приложения в приложении Spring. Те приведены ниже:

  1. Через ApplicationContextAware :

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class AppContextProvider implements ApplicationContextAware {
    
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    }
    

Здесь setApplicationContext(ApplicationContext applicationContext) метод вы получите приложениеContext

ApplicationContextAware

Интерфейс, который будет реализован любым объектом, который хочет получить уведомление ApplicationContext, в котором он выполняется. Реализация этого интерфейса имеет смысл, например, когда объект требует доступа к набору сотрудничающие бобы.

  1. Через Autowired :

    @Autowired
    private ApplicationContext applicationContext;
    

Здесь ключевое слово @Autowired предоставит applicationContext. Autowired имеет некоторые проблемы. Это создаст проблему при юнит-тестировании.

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