Як ApplicationContextAware працює навесні?


82

Навесні, якщо боб реалізує ApplicationContextAware, то він може отримати доступ до applicationContext. Тому він може отримувати інші боби. напр

public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;     

    public void setApplicationContext(ApplicationContext context) throws BeansException {
      applicationContext = context;
    }

    public static ApplicationContext getApplicationContext() {
      return applicationContext;
    }
}

Тоді SpringContextUtil.getApplicationContext.getBean("name")можна отримати квасоля "ім'я".

Для цього ми повинні помістити це SpringContextUtilвсередину applications.xml, наприклад

<bean class="com.util.SpringContextUtil" />

Тут квасоля SpringContextUtilне включає властивість applicationContext. Думаю, коли ініціалізується Spring Bean, ця властивість встановлюється. Але як це робиться? Як викликається метод setApplicationContext?


13
Весна - це магія.
Обійміть

Відповіді:


99

Коли Spring створює екземпляри бобів, він шукає пару інтерфейсів, таких як ApplicationContextAwareі InitializingBean. Якщо вони знайдені, викликаються методи. Наприклад (дуже спрощено)

Class<?> beanClass = beanDefinition.getClass();
Object bean = beanClass.newInstance();
if (bean instanceof ApplicationContextAware) {
    ((ApplicationContextAware) bean).setApplicationContext(ctx);
}

Зверніть увагу, що в новішій версії може бути краще використовувати анотації, а не реалізовувати специфічні для інтерфейсу інтерфейси. Тепер ви можете просто використовувати:

@Inject // or @Autowired
private ApplicationContext ctx;

4
Щиро дякую, Це те, що я хочу! Можливо, мені потрібно прочитати якийсь весняний код, щоб зрозуміти, як працює весна.
Джиммі

2
Краще використовувати @Autowired для більшості випадків, але є й інші, де це може не спрацювати, наприклад, коли у вас є "Компонент", який є одностороннім, але вам потрібно ввести компонент, що має обсяг сеансу. Оскільки залежності автоматично підключаються при створенні контексту програми, ви насправді не будете вводити компонент сеансу, маючи посилання на контекст програми, ви можете отримати програму сеансу в програмі, яка правильно поверне екземпляр сеансу.
raspacorp

Я би очікував, що Spring замість цього вводить динамічно генерований проксі-клас - такий клас має область застосування, але при доступі він делегує екземпляр області сесії або видає виняток, оскільки немає запиту, прив'язаного до поточного потоку
xorcus

@raspacorp, якщо не вдається отримати з ін'єкційного файлу сфери дії sesson ApplicationContext, тоді його неможливо отримати ApplicationContextAware instanceні з одного. Тому що ApplicationContextAware instanceотримує боб з того самого applicationContextоб’єкта, що і той, що вводиться.
Тійна

10

Весняний вихідний код, щоб пояснити, як працює ApplicationContextAware,
коли ви використовуєте ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
In AbstractApplicationContextclass, refresh()метод має такий код:

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

введіть цей метод, beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));додасть ApplicationContextAwareProcessor до AbstractrBeanFactory.

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...........

Коли весна ініціалізує bean у AbstractAutowireCapableBeanFactory, в методі initializeBean, виклик applyBeanPostProcessorsBeforeInitializationдля реалізації процесу post bean. процес включає ін'єкцію applicationContext.

@Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

коли BeanPostProcessor реалізує Objectдля виконання методу postProcessBeforeInitialization, наприклад ApplicationContextAwareProcessor, доданого раніше.

private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
                        new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

0

Інтерфейс, який повинен бути реалізований будь-яким об'єктом, який хоче отримувати повідомлення про ApplicationContext, в якому він працює.

вище витягнуто з веб-сайту Spring doc https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html .

Отож, здавалося, це було викликано, коли запущений контейнер Spring, якщо ви хочете щось зробити в той час.

Він просто має один метод встановити контекст, тож ви отримаєте контекст і зробите щось для того, щоб щось зробити вже зараз у контексті, я думаю.


-1

ApplicationContextAware Interface, поточний контекст програми, за допомогою якого ви можете викликати служби контейнера spring. Ми можемо отримати поточний екземпляр applicationContext, введений методом нижче в клас

public void setApplicationContext(ApplicationContext context) throws BeansException.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.