Spring hook interface Aware

Preface

When we write code, sometimes we want to use the underlying components of Spring, such as ApplicationContext, BeanFactory, etc

Then we implement the hook method xxxAware provided by Spring. When an object is created, the method specified by the interface is called to inject the relevant components.

Aware interface

 1 /**
 2  * A marker superinterface indicating that a bean is eligible to be notified by the
 3  * Spring container of a particular framework object through a callback-style method.
 4  * The actual method signature is determined by individual subinterfaces but should
 5  * typically consist of just one void-returning method that accepts a single argument.
 6  *
 7  * <p>Note that merely implementing {@link Aware} provides no default functionality.
 8  * Rather, processing must be done explicitly, for example in a
 9  * {@link org.springframework.beans.factory.config.BeanPostProcessor}.
10  * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
11  * for an example of processing specific {@code *Aware} interface callbacks.
12  *
13  * @author Chris Beams
14  * @author Juergen Hoeller
15  * @since 3.1
16  */
17 public interface Aware {}

A marked super interface indicates that the bean will be noticed by the spring container through a callback style. This is what I call the hook method.

We can see the following pictures. There are many interfaces to implement Aware. They are all Spring's own components. We can easily use them through Aware.

 

Here are some important interfaces that I often use.

Aware sub interface Description
BeanNameAware Get the name of the Bean in the container
BeanFactoryAware Gets the current BeanFactory so that the container's services can be called
ApplicationContextAware Most functions of the IOC container can be used for injection
MessageSourceAware Get Message Source related text information
EmbeddedValueResolverAware Value parsers, such as {} {}, etc
EnvironmentAware Environment resolver, which is very useful when you can take properties

 

ApplicationContextAware interface

 1 public interface ApplicationContextAware extends Aware {
 2 
 3     /**
 4      * Set the ApplicationContext that this object runs in.
 5      * Normally this call will be used to initialize the object.
 6      * <p>Invoked after population of normal bean properties but before an init callback such
 7      * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
 8      * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
 9      * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
10      * {@link MessageSourceAware}, if applicable.
11      * @param applicationContext the ApplicationContext object to be used by this object
12      * @throws ApplicationContextException in case of context initialization errors
13      * @throws BeansException if thrown by application context methods
14      * @see org.springframework.beans.factory.BeanInitializationException
15      */
16     void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
17 
18 }

This can get Spring's IOC container. With this IOC container, you can have most of Spring's functions.

 

Let's take ApplicationContextAware as an example. Directly inheriting the interface of XxxAware, you can get the corresponding fields.

 1 @Component
 2 @Slf4j
 3 public class Person implements ApplicationContextAware, BeanFactoryAware,
 4         BeanNameAware, EnvironmentAware, EmbeddedValueResolverAware {
 5 
 6     @Override
 7     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 8         log.info("applicationContext = {}", applicationContext.getBean("person"));
 9     }
10 
11     @Override
12     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
13         log.info("beanFactory = {}", beanFactory.containsBean("person"));
14     }
15 
16     @Override
17     public void setBeanName(String name) {
18         log.info("name = {}", name);
19     }
20 
21     @Override
22     public void setEmbeddedValueResolver(StringValueResolver resolver) {
23         // Character parser
24         log.info("val = {}", resolver.resolveStringValue("#{5 * 10}"));
25     }
26 
27     @Override
28     public void setEnvironment(Environment environment) {
29         // This can get the value of the environment variable
30         log.info("app = {}", environment.getProperty("app.secret"));
31     }
32 }

Result:

1 2020-04-04 21:35:39.474 [main] [] INFO  - [com.gdufe.osc.controller.Person java:37] [name = person]
2 2020-04-04 21:35:39.475 [main] [] INFO  - [com.gdufe.osc.controller.Person java:32] [beanFactory = true]
3 2020-04-04 21:35:39.475 [main] [] INFO  - [com.gdufe.osc.controller.Person java:48] [app = wenbochang888]
4 2020-04-04 21:35:39.491 [main] [] INFO  - [com.gdufe.osc.controller.Person java:42] [val = 50]
5 2020-04-04 21:35:39.493 [main] [] INFO  - [com.gdufe.osc.controller.Person java:27] [applicationContext = com.gdufe.osc.controller.Person@24386839]

 

The implementation principle of the bottom layer of Aware interface

Let's look at the following code

 1 class ApplicationContextAwareProcessor implements BeanPostProcessor {
 2 
 3     @Override
 4     @Nullable
 5     public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
 6         
 7         .....
 8         invokeAwareInterfaces(bean);
 9         .....
10 
11         return bean;
12     }
13 
14     private void invokeAwareInterfaces(Object bean) {
15         if (bean instanceof Aware) {
16             if (bean instanceof EnvironmentAware) {
17                 ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
18             }
19             if (bean instanceof EmbeddedValueResolverAware) {
20                 ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
21             }
22             if (bean instanceof ResourceLoaderAware) {
23                 ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
24             }
25             if (bean instanceof ApplicationEventPublisherAware) {
26                 ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
27             }
28             if (bean instanceof MessageSourceAware) {
29                 ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
30             }
31             if (bean instanceof ApplicationContextAware) {
32                 ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
33             }
34         }
35     }
36 }

Let me explain the BeanPostProcessor method a little bit here. Before and after initializing the bean, you can execute the corresponding methods. Similar to AOP.

Then the application context aware processor is easy to understand.

Call the postProcessBeforeInitialization method before initialization of a bean instance. Then judge whether the bean has implemented the corresponding aware interface, and set the aware in, which is very convenient.

Tags: Java Spring

Posted on Wed, 08 Apr 2020 07:14:52 -0700 by fredouille