An overview,

No matter in our daily development, or when we look at spring source code, we will encounter Aware interface. From the English translation, what Aware does is to find something.

The gist of the annotation is that Aware is a markup superinterface (top-level interface) that indicates that a Bean is eligible to fetch the underlying components of the Spring container in the form of callback methods. The actual callback methods are defined in each subinterface, and usually a subinterface contains only a method with one argument and a return value of void.

To put it bluntly: any Bean that implements the Aware subinterface can get a Spring underlying component.

If you want to use spring’s underlying components, such as ApplicationContext, Beanfactory, XXX, etc., you just need to make the custom components implement xxxAware. Some of spring’s underlying components are injected into custom beans. Looking at the source code, you can see that there are so many interfaces, each of which has its own underlying spring counterpart, such as:

  • Bean implementing the BeanNameAware interface: Gets the BeanName
  • Bean that implements the BeanFactoryAware interface: takes the BeanFactory component object
  • Bean that implements the EnvironmentAware interface: Gets the Environment component object
  • Beans that implement the XXXAware interface: XXX component objects can be obtained by implementing setXXX methods

Ii. Case analysis

Here are some examples of common interfaces implemented to use some of Spring’s underlying components

/ / start the class
@Test
public void TestMain(a) {
    // Create an IOC container
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
}

// The bean to inject
@Component
public class User implements ApplicationContextAware.BeanNameAware.EmbeddedValueResolverAware {
    private ApplicationContext applicationContext;
    // Get the beans in the Spring container from the context object
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("Incoming IOC:" + applicationContext);
        this.applicationContext = applicationContext;
    }
    // Get the bean name
    public void setBeanName(String s) {
        System.out.println("Current bean name:" + s);
    }
    // Parse some strings, placeholders, etc
    public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
        String resolveStringValue = stringValueResolver.resolveStringValue("Hello ${OS. The name}");
        System.out.println(The parsed string is:+ resolveStringValue); }}/ / configuration class
@Configuration
public class AppConfig {
    @Bean
    public User User(a){
        return newUser(); }}Copy the code

Run the startup class and you can see the following output:

Here to Aware, for example, the three interfaces of ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware

  • ApplicationContextAware: Get beans in the Spring container from context objects
  • BeanNameAware: Gets the bean name
  • EmbeddedValueResolverAware: parsing some string, a placeholder, etc

Third, source tracking

In fact, each sub-interface is handled by the corresponding xxxProcess, that is, the corresponding post-processor, and these XXxProcesses are interfaces to BeanPostProcess, For example ApplicationContextAware is processed by ApplicationContextAwareProcess ApplicationContextAwareProcess BeanPostProcess is realized

ApplicationContextAware = ApplicationContextAware = ApplicationContextAware

Debug breakpoints in the setApplicationContext method:

Method through the call stack, can see ApplicationContextAwareProcessor call postProcessBeforeInitialization method,

  • Check whether the interface is xxxAware. If yes, continue
  • Inject through invokeAwareInterfaces
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // Check whether the interface is xxxAware
    if(! (beaninstanceofEnvironmentAware) && ! (beaninstanceofEmbeddedValueResolverAware) && ! (beaninstanceofResourceLoaderAware) && ! (beaninstanceofApplicationEventPublisherAware) && ! (beaninstanceofMessageSourceAware) && ! (beaninstanceofApplicationContextAware) && ! (beaninstanceof ApplicationStartupAware)) {
        return bean;
    } else {
        AccessControlContext acc = null;
        if(System.getSecurityManager() ! =null) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if(acc ! =null) {
            AccessController.doPrivileged(() -> {
                this.invokeAwareInterfaces(bean);
                return null;
            }, acc);
        } else {
            // Inject accordingly in this method
            this.invokeAwareInterfaces(bean);
        }

        returnbean; }}Copy the code

Call the invokeAwareInterfaces method, which is the User object. Pass in the bean to be injected and do the following:

  1. Check whether it is an xxxAware interface
  2. If so, get XXX and call setxxx method for injection

Here, take ApplicationContextAware as an example to realize the ApplicationContextAware interface, The User object is converted into the ApplicationContextAware interface and injected by calling the setApplicationContext method

private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
    }

    if (bean instanceof EmbeddedValueResolverAware) {
        ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    }

    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 ApplicationStartupAware) {
        ((ApplicationStartupAware)bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
    }

    if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext); }}Copy the code

Four,

  • The bean is used at initialization timexxxProcessThe post-processor determines whether the bean isxxxAwareinterface
  • If so, the component is passed in by calling the appropriate set method