Let’s talk about Spring’s Aware interface


Insert image description here

0.Preface

Background: Recently, a developer classmate asked me that there are many places in the project that implement the Aware interface and what its function is. He said that the reason was that in our project code, we saw that some codes implemented the ResourceLoaderAware, BeanNameAware, ApplicationContextAware, and BeanFactoryAware interfaces. 我没法直接笼统回答,也没有法一句话简答,只好侧面的告诉他Aware接口是Spring 为了提供拓展的一种设计思想。凡是带Aware后缀的接口。主要作用是为了让实现了该接口的Bean在Spring容器中具有回调功能。通过实现不同子接口,可以让Bean在运行过程中获取Spring容器内部的一些特定对象.

In order to further demonstrate the answer I gave, I took the time today to take a look at the implementation or indirect implementation classes of Aware in the project. Including the Spring framework and third-party frameworks, there are approximately 673 implementations using it.
Insert image description here

1.What is the Aware interface?

Let’s first take a look at the definition of super interfaces of all Aware interfaces. org.springframework.beans.factory.Aware
Insert image description here
According to the comments, we can understandorg.springframework.beans.factory.Aware Mark the super interface to indicate that a bean is eligible to receive specific framework objects passed by the Spring container through callbacks. The actual method signature is determined by the individual sub-interface, but should usually only contain a single argument that returns void.. This translation is a bit abstract and popular 这个Aware接口是Spring框架中的一个机制,允许Bean通过回调方式与Spring容器进行交互,并获取特定的框架对象,以便在Bean的逻辑中进行相应的处理.

There are a series of Aware interfaces in the Spring framework. These interfaces are used to allow beans that implement them to obtain some objects or resources of the Spring framework. These resources include ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher, etc.

Aware interface names usually end with Aware, such as the most common ApplicationContextAware and BeanFactoryAware, which allow Beans to obtain ApplicationContext and BeanFactory respectively.

For example, if a Bean implements the ApplicationContextAware interface, when Spring creates the Bean, it will automatically call the setApplicationContext method and pass in the ApplicationContext as a parameter, so that the Bean can obtain Spring's ApplicationContext at runtime.

It is generally not recommended to use the Aware interface directly, because this will cause the code to be too tightly coupled with the Spring framework. In most cases, we can obtain Spring framework resources through dependency injection or other better methods. Unless in order to achieve a specific function, we will implement the corresponding Aware interface to obtain resources.

2.The design purpose of the Aware interface

The purpose of this design is to allow beans to interact with other parts of the Spring framework, rather than just passively being created and managed by the Spring container.

I think this design has another advantage. You can directly know the capabilities of this Aware interface through the name + Aware suffix. You can directly obtain or operate some resources of the Spring framework. In other words, it is actually a manifestation of the relatively high structure of Spring that enables the Spring framework to "allow ordinary Java objects to use the full functionality of the framework."

So, generally speaking, the rule for interface names is: [aware/obtained resources or environment] + AwareFor example BeanFactoryAware, ResourceLoaderAware.
Insert image description here

Let's observe that the naming rules for the Aware interface and its sub-interfaces are very simple. Usually, the corresponding function name is added after Aware. These function names usually represent the resources or the environment that the class that implements the interface needs to obtain. For example:

  • ApplicationContextAware: means that the class that implements this interface can be aware of the application context ( ApplicationContext).

  • BeanFactoryAware: Classes that implement this interface can be aware of the Bean factory ( BeanFactory).

  • BeanNameAware: The class that implements this interface can perceive the name of the Bean.

  • ServletContextAwareIt means that the class that implements this interface can be aware of the Servlet context ( ServletContext).

  • MessageSourceAware: Classes that implement this interface can be aware of the message source ( MessageSource).

- ResourceLoaderAware: Classes that implement this interface are aware of resource loaders ( ResourceLoader).

3.Detailed explanation

Let’s take a look at the usage scenarios and usage of these common Aware interfaces respectively ApplicationContextAware. , BeanFactoryAware, BeanNameAware, ServletContextAware, MessageSourceAware.ResourceLoaderAware

3.1. ApplicationContextAware

This interface is too common for us. Used in almost most projects. Because it can be obtained. It is implemented when a class needs to access all services in the Spring application context (such as other beans, life cycle events, specific configuration, etc.).

ApplicationContextAwareIt is an interface of the Spring framework. When a class implements this interface, then this class will have the ability to access the Spring ApplicationContext. In other words, this class can directly obtain all beans in the spring container.

This interface mainly has one method: setApplicationContext(ApplicationContext applicationContext). The Spring container will detect all beans. If it is found that a bean implements ApplicationContextAwarethe interface, the Spring container will automatically call the bean's method after creating the bean. setApplicationContext(ApplicationContext applicationContext)When calling this method, the container itself will be passed to the bean as a parameter. In this way, when the bean needs to use the functionality of the container, it can use this incoming parameter.

This interface is usually used when you need to access the functionality of the container itself, or when you need to access other beans in the container. For example, when a bean needs to dynamically find other beans, or needs to use the container's event publishing function, it can obtain the container object by implementing this interface.

Under normal circumstances, we do not need to implement this interface directly, because Spring provides ApplicationObjectSupporta class that implements ApplicationContextAwarethe interface. We can simplify our code by inheriting this class.

Let us give an example to illustrate

Below is a specific computing service example that uses ApplicationContextAwarethe interface to obtain an account service.
CalculationServiceThe class implements ApplicationContextAwarethe interface and overrides setApplicationContextthe method. When the Spring container creates CalculationServicean instance, it will automatically call CalculationServicethe setApplicationContextmethod and pass the container itself as a parameter.
Then, CalculationServiceyou can applicationContextaccess the container itself through the member variables to obtain the information in the container AccountServiceand use this service to perform interest calculations.

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

public class CalculationService implements ApplicationContextAware {
    
    

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        this.applicationContext = applicationContext;
    }

    public double calculateInterest(String accountId, double principal, double rate, double time) {
    
    
        // 通过 applicationContext 获取 Spring 容器中的 AccountService bean
        AccountService accountService = applicationContext.getBean(AccountService.class);
        // 使用获取到的 AccountService 进行操作
        double interest = accountService.calculateInterest(principal, rate, time);
        return interest;
    }
}

3.2. BeanFactoryAware

This interface is implemented when a class needs to access the Spring BeanFactory to gain low-level access to the Spring framework.

Let’s take an example to understand. For example, most of our projects will send notifications, which may require email, WeChat, SMS, Feishu, etc. These configurations can allow users to customize the configuration. In the future, the system may also expand other types of notifications such as DingTalk. In order to meet this demand. We use to BeanFactoryAwarecreate a service locator (Service Locator). Service locator is used to centrally manage and find services. In complex applications, this can make the code easier to manage and extend.

First consider that we have many services, such as EmailService, SMSService, PushNotificationServiceetc., all implementing an MessageServiceinterface. We can use BeanFactoryAwareto create a service locator that can fetch any service we need.

@Service
public class ServiceLocator implements BeanFactoryAware {
    
    

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    
    
        this.beanFactory = beanFactory;
    }

    public MessageService getService(String serviceName) {
    
    
        return (MessageService) beanFactory.getBean(serviceName);
    }
}

Then where the service is needed, we can use it like this:

@Service
public class MessageClient {
    
    

    private final ServiceLocator serviceLocator;

    public MessageClient(ServiceLocator serviceLocator) {
    
    
        this.serviceLocator = serviceLocator;
    }

    public void sendMessage(String message, String serviceName) {
    
    
        MessageService service = serviceLocator.getService(serviceName);
        service.send(message);
    }
}

ServiceLocatorBy implementing BeanFactoryAwarethe interface, you can obtain the Spring container, and then obtain the corresponding service based on the service name. MessageClientBy ServiceLocatorbeing able to flexibly select the services you need, the code is made more flexible and testable.

The remaining four are also very common. Let’s do it tomorrow when I have time. It’s too late today, so let’s stop here.

3.3. BeanNameAware

A class implements this interface when it needs to know the name of its bean defined in the Spring configuration.

3.4. ServletContextAware

This interface will be implemented when a class needs to obtain the ServletContext, usually used in web applications that need to access the Servlet API. For example, you need to read some real paths in web applications, or servlet context attributes, etc.

3.5. MessageSourceAware

When a class needs to load some message resources, such as some internationalized strings, it will implement this interface.

3.6. ResourceLoaderAware

When a class needs to load some file resources, it will implement this interface. This allows you to more easily load resources from the classpath or file system.

4. Reference documents

  1. Spring official documentation: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-aware
  2. Spring Framework API documentation ( BeanFactoryAwaresection about ): https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactoryAware.html
  3. Explanation of service locator pattern: https://www.martinfowler.com/eaaCatalog/serviceLocator.html
  4. Example of using Spring to implement the service locator pattern: https://www.baeldung.com/spring-service-locator

Guess you like

Origin blog.csdn.net/wangshuai6707/article/details/133040002