ApplicationContextAware hoạt động như thế nào trong Spring?


82

Vào mùa xuân, nếu một hạt đậu thực hiện ApplicationContextAware, thì nó có thể truy cập vào applicationContext. Do đó nó có thể lấy được các loại đậu khác. ví dụ

public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;     

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

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

Sau đó, SpringContextUtil.getApplicationContext.getBean("name")có thể nhận được đậu "tên".

Để làm điều này, chúng ta nên đặt nó SpringContextUtilbên trong applications.xml, ví dụ:

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

Ở đây bean SpringContextUtilkhông bao gồm thuộc tính applicationContext. Tôi đoán khi khởi tạo Spring bean, thuộc tính này được đặt. Nhưng điều này được thực hiện như thế nào? Làm thế nào để phương thức setApplicationContextđược gọi?


12
Mùa xuân là Phép thuật. Nắm lấy điều kỳ diệu
rosenthal

Câu trả lời:


98

Khi mùa xuân khởi tạo bean, nó sẽ tìm kiếm một vài giao diện như ApplicationContextAwareInitializingBean. Nếu chúng được tìm thấy, các phương thức sẽ được gọi. Ví dụ: (rất đơn giản)

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

Lưu ý rằng trong phiên bản mới hơn, có thể tốt hơn là sử dụng chú thích, thay vì triển khai các giao diện dành riêng cho mùa xuân. Bây giờ bạn có thể chỉ cần sử dụng:

@Inject // or @Autowired
private ApplicationContext ctx;

4
Cảm ơn bạn rất nhiều, Đây là những gì tôi muốn! Có lẽ tôi cần đọc một số mã số mùa xuân để hiểu cách hoạt động của mùa xuân.
Jimmy

2
Tốt hơn là sử dụng @Autowosystem trong hầu hết các trường hợp nhưng có những trường hợp khác có thể không hoạt động, chẳng hạn như khi bạn có "@Component" là một singleton nhưng bạn cần phải chèn một bean có phạm vi phiên. Vì các phần phụ thuộc được tự động tải trong quá trình tạo ngữ cảnh ứng dụng, bạn sẽ không thực sự đưa vào session bean, bằng cách tham chiếu đến ngữ cảnh ứng dụng, bạn có thể lấy session bean theo chương trình sẽ trả về phiên bản session một cách chính xác.
raspacorp,

Tôi mong đợi Spring sẽ chèn một lớp proxy được tạo động để thay thế - một lớp như vậy có phạm vi ứng dụng, nhưng khi được truy cập, nó ủy quyền cho một cá thể phạm vi phiên hoặc ném một ngoại lệ, nó không có yêu cầu ràng buộc với luồng hiện đang chạy
xorcus

@raspacorp nếu không thể nhận bean phạm vi sesson từ được tiêm ApplicationContextthì cũng không thể nhận được từ ApplicationContextAware instanceđó. Bởi vì ApplicationContextAware instancenhận được một hạt đậu từ cùng một applicationContextđối tượng như đối tượng được tiêm.
Tiina

10

Mã nguồn Spring để giải thích cách ApplicationContextAware hoạt động
khi bạn sử dụng ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Trong AbstractApplicationContextlớp, refresh()phương thức có mã sau:

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

nhập phương thức này, beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));sẽ thêm ApplicationContextAwareProcessor vào 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));
...........

Khi mùa xuân khởi tạo bean trong AbstractAutowireCapableBeanFactory, trong phương thức initializeBean, hãy gọi applyBeanPostProcessorsBeforeInitializationđể thực hiện quá trình bean post. quá trình này bao gồm việc đưa applicationContext vào.

@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;
    }

khi BeanPostProcessor triển khai Object để thực thi phương thức postProcessBeforeInitialization, ví dụ như phương thức ApplicationContextAwareProcessorđã thêm trước đó.

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

Giao diện được thực hiện bởi bất kỳ đối tượng nào muốn được thông báo về ApplicationContext mà nó chạy trong đó.

ở trên được trích từ trang web tài liệu Spring https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html .

Vì vậy, nó dường như được gọi khi Spring container đã bắt đầu, nếu bạn muốn làm gì đó tại thời điểm đó.

Nó chỉ có một phương pháp để thiết lập ngữ cảnh, vì vậy bạn sẽ có được bối cảnh và làm điều gì đó để thực hiện ngay bây giờ đã có trong ngữ cảnh, tôi nghĩ.


-1

ApplicationContextAware Interface, bối cảnh ứng dụng hiện tại, qua đó bạn có thể gọi các dịch vụ vùng chứa mùa xuân. Chúng ta có thể lấy thể hiện applicationContext hiện tại được đưa vào bằng phương thức dưới đây trong lớp

public void setApplicationContext(ApplicationContext context) throws BeansException.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.