Как ApplicationContextAware работает в Spring?

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" />

Здесь bean-компонент SpringContextUtilне включает свойство applicationContext. Я предполагаю, что при инициализации Spring bean это свойство устанавливается. Но как это сделать? Как вызывается метод setApplicationContext?

Джимми
источник
13
Весна - это волшебство. Обнимите волшебство
Розенталь

Ответы:

99

Когда Spring создает beans, он ищет пару интерфейсов, например ApplicationContextAwareи InitializingBean. Если они обнаружены, вызываются методы. Например (очень упрощенно)

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

Обратите внимание, что в более новой версии может быть лучше использовать аннотации, чем реализовывать интерфейсы, специфичные для Spring. Теперь вы можете просто использовать:

@Inject // or @Autowired
private ApplicationContext ctx;
Божо
источник
4
Большое спасибо, это то, что я хочу! Возможно, мне нужно прочитать код Spring, чтобы понять, как работает Spring.
Джимми
2
В большинстве случаев лучше использовать @Autowired, но есть и другие, где это может не сработать, например, когда у вас есть «@Component», который является синглтоном, но вам нужно внедрить bean-компонент с областью сеанса. Поскольку зависимости автоматически подключаются при создании контекста приложения, у вас действительно не будет внедренного сеансового компонента, имея ссылку на контекст приложения, вы можете программно получить компонент сеанса, который вернет экземпляр сеансового компонента правильно.
raspacorp
Я бы ожидал, что Spring вместо этого вводит динамически сгенерированный прокси-класс - такой класс имеет область приложения, но при доступе он делегирует экземпляр области сеанса или выдает исключение, если нет запроса, привязанного к
текущему
@raspacorp, если бин области видимости сессона не может быть получен из внедренного ApplicationContext, то его нельзя получить ApplicationContextAware instanceни из одного другого. Потому что ApplicationContextAware instanceполучает bean-компонент из того же applicationContextобъекта, что и введенный.
Tiina
10

Исходный код Spring, объясняющий, как работает ApplicationContextAware,
когда вы используете класс ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
In AbstractApplicationContext, 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));
...........

Когда Spring инициализирует bean-компонент в AbstractAutowireCapableBeanFactoryметоде initializeBean, вызывается applyBeanPostProcessorsBeforeInitializationдля реализации пост-процесса 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 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html .

Итак, казалось, что он вызывается при запуске контейнера Spring, если вы хотите что-то сделать в это время.

У него есть только один метод для установки контекста, так что вы получите контекст и сделаете что-нибудь, что уже в контексте, я думаю.

Ю Чай
источник
-1

ApplicationContextAware Интерфейс, текущий контекст приложения, через который вы можете вызывать службы контейнера Spring. Мы можем получить текущий экземпляр applicationContext, введенный нижеприведенным методом в классе

public void setApplicationContext(ApplicationContext context) throws BeansException.
техесантош
источник