Aware of SpringIoc container | JD Cloud technical team

1 Introduction

Aware is a marker superinterface provided by Spring, indicating that the bean is eligible to be notified by the Spring container to a specific framework object through a callback-style method to obtain one of the methods of an instance of a specific object in the container. The actual method signature is determined by the individual subinterfaces, but usually consists of only a void-returning method accepting a single parameter.

2 Nine Aware built-in implementations in Spring

|--Aware
    |--BeanNameAware
    |--BeanClassLoaderAware
    |--BeanFactoryAware
    |--EnvironmentAware
    |--EmbeddedValueResolverAware
    |--ResourceLoaderAware
    |--ApplicationEventPublisherAware
    |--MessageSourceAware
    |--ApplicationContextAware



The 9 built-in implementations are divided into two categories, the first three are direct calls, and the last 6 are indirect callbacks through ApplicationContextAwareProcessor post processors

2.1 BeanNameAware

public interface BeanNameAware extends Aware {

       /**
        *设置创建此bean的bean工厂中的bean的名称。
        *在普通bean属性填充之后但在
        *初始化之前回调,如{@link InitializingBean#afterPropertiesSet()}
        *或自定义初始化方法。
        * @param name工厂中bean的名称。
        *注意,此名称是工厂中使用的实际bean名称,这可能
        *与最初指定的名称不同:特别是对于内部bean
        * names,实际的bean名称可以通过添加
        *“#…”后缀。使用{@link BeanFactoryUtils#originalBeanName(String)}
        *方法提取原始bean名称(不带后缀),如果需要的话。
        * /
	void setBeanName(String name);

}



To implement the BeanNameAware interface, you need to implement the setBeanName() method. This method simply returns our current beanName. The superficial function of this interface is to let the bean that implements this interface know its name in the spring container, and the official meaning is this interface It is more used in the framework code of spring, and it should not be recommended in the actual development environment, because spring thinks that the name of the bean is not very deeply connected with the bean, (indeed, apart from the spring API, if we get the bean The name of the bean is actually not very meaningful. We have not obtained the class of the bean, only the name of the bean, and we have no way to start. On the contrary, because the name of the bean may be the unique identifier of the bean in the spring container, that is to say, In beanDefinitionMap, the key value is the name, and spring can obtain all the characteristics of the bean according to this key value), so spring says that this is not an unnecessary dependency.

2.2 BeanClassLoaderAware

public interface BeanClassLoaderAware extends Aware {

   /**
    *提供bean {@link ClassLoader}类加载器的回调
    *一个bean实例在属性的填充之后但在初始化回调之前调用
    * {@link InitializingBean
    * {@link InitializingBean#afterPropertiesSet()}
    *方法或自定义初始化方法。
    * @param类加载器拥有的类加载器;可能是{@code null}在例如,必须使用默认的{@code ClassLoader}
    * 获取的{@code ClassLoader}
    * {@link org.springframework.util.ClassUtils#getDefaultClassLoader()}
    * /
   void setBeanClassLoader(ClassLoader classLoader);

}



Provides callbacks for class modifiers after bean properties are populated but before initialization. Let the managed bean itself know which type of loader it is responsible for loading.

2.3 BeanFactoryAware

public interface BeanFactoryAware extends Aware {

   /**
    * 为bean实例提供所属工厂的回调。
    * 在普通bean属性填充之后调用但在初始化回调之前,如
    * {@link InitializingBean#afterPropertiesSet()}或自定义初始化方法。
    * @param beanFactory拥有beanFactory(非空)。bean可以立即调用工厂上的方法。
    * @在初始化错误时抛出BeansException
    * @参见BeanInitializationException
    * /
   void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}



Callback to the bean factory after the bean properties are populated and before initialization. A bean that implements the BeanFactoηAware interface can directly access the Spring container. After being created by the container, it will have a reference to the Spring container, which can be used to dynamically obtain the bean loaded by the spring factory according to the incoming parameters.

2.4 EnvironmentAware

public interface EnvironmentAware extends Aware {

   /**
    * 设置该对象运行的{@code环境}。
    */
   void setEnvironment(Environment environment);

}



Sets the object to run on. For all beans registered in the Spring container, as long as the bean implements the EnvironmentAware interface and rewrites the setEnvironment method, the property values ​​​​configured in the application.properties configuration file can be obtained when the project starts, so that No need for us to write the magic value into the code.

2.5 EmbeddedValueResolverAware

public interface EmbeddedValueResolverAware extends Aware {

   /**
    * 设置StringValueResolver用于解析嵌入的定义值。
    */
   void setEmbeddedValueResolver(StringValueResolver resolver);

}



When obtaining the attribute value of the properties file based on Spring, the @Value method is generally used to inject the attribute value of the configuration file, but @Value must be used under the Bean life cycle management of Spring, such as the class being @Controller, @Service, @Component etc. annotations. For example, in some abstract classes, use EmbeddedValueResolverAware to parse configuration files based on the way Spring parses @Value.

2.6 ResourceLoaderAware

public interface ResourceLoaderAware extends Aware {

   /**
    *设置该对象运行的ResourceLoader。这可能是一个ResourcePatternResolver,它可以被检查
    *通过{@code instanceof ResourcePatternResolver}。另请参阅
    * {@code ResourcePatternUtils。getResourcePatternResolver}方法。
    * <p>在填充普通bean属性之后但在init回调之前调用
    *像InitializingBean的{@code afterPropertiesSet}或自定义初始化方法。
    *在ApplicationContextAware的{@code setApplicationContext}之前调用。
    * @param resourceLoader该对象使用的resourceLoader对象
    * @ @ springframework.core. io.support.resourcepatternresolver
    * @ @ resourcepatternutils #获取resourcepatternresolver
    * /
   void setResourceLoader(ResourceLoader resourceLoader);

}



ResourceLoaderAware is the special marker interface that expects to have an object referenced by a ResourceLoader. When a class that implements the ResourceLoaderAware interface is deployed to the application context (such as a bean managed by Spring), it will be recognized as ResourceLoaderAware by the application context. Then the application context will call the setResourceLoader(ResourceLoader) method and pass itself as a parameter to the method (remember, all application contexts in Spring implement the ResourceLoader interface).

Since the ApplicationContext is the ResourceLoader, the bean can implement the ApplicationContextAware interface and directly use the provided application context to load resources, but it is usually more suitable to use a specific ResourceLoader implementation that meets all needs. In this way, the code only needs to depend on the resource loading interface, which can be regarded as an auxiliary interface, instead of relying on the entire Spring ApplicationContext interface.

2.7 ApplicationEventPublisherAware

public interface ApplicationEventPublisherAware extends Aware {

   /**
    *设置该对象运行的ApplicationEventPublisher。
    * <p>在普通bean属性填充之后但在init之前调用像InitializingBean的afterPropertiesSet或自定义初始化方法。
    *在ApplicationContextAware的setApplicationContext之前调用。
    *该对象使用的事件发布者
    * /
   void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);

}



ApplicationEventPublisherAware is an interface provided by Spring for injecting ApplicationEventPublisher event publisher into Service. Using this interface, our own Service has the ability to publish events.

2.8 MessageSourceAware

public interface MessageSourceAware extends Aware {

   /**
    *设置该对象运行的MessageSource。
    * <p>在普通bean属性填充之后但在init之前调用像InitializingBean的afterPropertiesSet或自定义初始化方法。
    *在ApplicationContextAware的setApplicationContext之前调用。
    * @param messageSource消息源
    * /
   void setMessageSource(MessageSource messageSource);

}



Get the message source so that you can get the text information, and the usage scenario is for internationalization.

2.9 ApplicationContextAware

public interface ApplicationContextAware extends Aware {

   /**
    *设置该对象运行的ApplicationContext。通常这个调用将用于初始化对象。
    * <p>在普通bean属性填充之后但在init回调之前调用
    *作为{@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
    *或自定义初始化方法。在{@link ResourceLoaderAware#setResourceLoader}之后调用,
    * {@link ApplicationEventPublisherAware#setApplicationEventPublisher}和
    * {@link MessageSourceAware},如果适用。
    * @param applicationContext该对象将使用的applicationContext对象
    * @在上下文初始化错误时抛出ApplicationContextException如果由应用程序上下文方法抛出,则抛出BeansException
    * @see org.springframework.beans.factory.BeanInitializationException
    * /
   void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}



The role of ApplicationContextAware is to easily obtain the Spring container ApplicationContext, so that the Bean in the container can be obtained. The ApplicationContextAware interface has only one method. If this method is implemented, Spring will automatically execute this method when creating the implementation class, and inject the ApplicationContext into this class. That is to say, Spring needs to instantiate this class when it starts (If it is lazy loading, it is instantiated when you need it). When instantiating this class, if it finds that it contains the ApplicationContextAware interface, sping will call the setApplicationContext method of this object and put the applicationContext Set into it.

3 Call timing in Spring

The Aware interface is triggered by Spring in the AbstractAutowireCapableBeanFactory.initializeBean(beanName, bean, mbd) method by calling the invokeAwareMethods(beanName, bean) method and applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName) to trigger the invocation of the Aware method

3.1 invokeAwareMethods

private void invokeAwareMethods(final String beanName, final Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof BeanNameAware) {
         ((BeanNameAware) bean).setBeanName(beanName);
      }
      if (bean instanceof BeanClassLoaderAware) {
         ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
      }
      if (bean instanceof BeanFactoryAware) {
         ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
      }
   }
}



Judgment and direct callback

3.2 applyBeanPostProcessorsBeforeInitialization

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



It is called indirectly through ApplicationContextAwareProcessor.postProcessBeforeInitialization(Object bean, String beanName), and is called back in the method invokeAwareInterfaces.

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
   AccessControlContext acc = null;

   if (System.getSecurityManager() != null &&
         (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
               bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
               bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
   }

   if (acc != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareInterfaces(bean);
            return null;
         }
      }, acc);
   }
   else {
      invokeAwareInterfaces(bean);
   }

   return bean;
}

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



4 Summary

Through the above analysis, we can know that in the initialization method in the Spring life cycle, before the initialization method is actually executed, the Aware call is triggered by the invokeAwareMethods method and the post-processor ApplicationContextAwareProcessor respectively. Then, why does Spring use two methods instead of What about using one of them?

Through this chapter, we have learned about the functions of the built-in interfaces in 9 and the different contextual information they can obtain.

Author: JD Retail Zeng Dengjun

Source: JD Cloud Developer Community

Graduates of the National People’s University stole the information of all students in the school to build a beauty scoring website, and have been criminally detained. The new Windows version of QQ based on the NT architecture is officially released. The United States will restrict China’s use of Amazon, Microsoft and other cloud services that provide training AI models . Open source projects announced to stop function development LeaferJS , the highest-paid technical position in 2023, released: Visual Studio Code 1.80, an open source and powerful 2D graphics library , supports terminal image functions . The number of Threads registrations has exceeded 30 million. "Change" deepin adopts Asahi Linux to adapt to Apple M1 database ranking in July: Oracle surges, opening up the score again
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4090830/blog/10086653