This article is from huawei Cloud community Aware Spring Bean by JavaLib Chen PI.

Sentient Spring beans

Normally, a Bean in Spring is Spring insensitive, that is, it does not know which Bean factory it was created by; Can’t sense its own id in the factory, namely beanName; There is no awareness of Spring ApplicationContext objects, etc.

If we want Spring beans to be aware of this information, we can get this information ourselves by some means and then set it to the Bean instance. The downside of this approach is that we need to get the information we need to be aware of ourselves, and then actively set it into the bean, resulting in a lot of redundant code. But the advantage is that it can be decoupled from Spring.

Of course, the Spring framework provides this extension capability to make a bean aware. Simply have the bean class implement a specific interface and override the methods in it. Spring then calls these overridden methods at some point in the bean’s life cycle, injecting the information it needs to be aware of. The disadvantage of this approach is that it needs to be coupled to Spring, but the advantage is that it reduces the amount of code and is simple.

Aware interface

For beans in Spring to gain some awareness, you need to implement specific interfaces that have a common parent, the Aware interface.

package org.springframework.beans.factory;

public interface Aware {
    
}
Copy the code

Aware is a markup interface that indicates that a bean can retrieve a specific object in the Spring container through a callback method. The specific method signatures are defined by the individual subinterfaces, but generally should contain only a method that takes a single argument and returns void.

Note that implementing the Aware interface alone does not provide default functionality. We typically implement a subinterface to Aware to obtain specific perceptual capabilities.

There are many subinterfaces to the Aware interface, such as BeanNameAware, BeanFactoryAware, ApplicationContextAware, EnvironmentAware, The use of the ApplicationEventPublisherAware, etc., introduce several commonly used below.

BeanNameAware interface

If the bean needs to know its beanName in the bean factory, that is, its name (identity) in the Spring container. This BeanNameAware interface can be implemented. The source of the BeanNameAware interface is shown below. There is only one method by which beanName is set to the bean.

package org.springframework.beans.factory;

public interface BeanNameAware extends Aware {
	void setBeanName(String name);
}
Copy the code

In fact, the bean we are using generally does not need to know its name in the beanFactory, which makes little sense. It is generally used in the Spring framework and is not recommended because it will cause beans to rely on the Spring API.

package com.chenpi; import org.springframework.beans.factory.BeanNameAware; import org.springframework.stereotype.Component; /** * @author * @version 1.0 * @description * @date 2022/4/3 */ @component public class Person implements BeanNameAware { private String beanName; @Override public void setBeanName(String name) { this.beanName = name; } public String getBeanName() { return beanName; }}Copy the code

Write the test unit and verify as follows:

package com.chenpi; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class ApplicationTests { @Autowired private Person person; @Test public void testValue() { System.out.println("Person BeanName:" + person.getBeanName()); Person BeanName: PersonCopy the code

BeanFactoryAware interface

If a Bean wants to be aware and configure its own BeanFactory object, it can implement the BeanFactoryAware interface. If needed, beans can collaborate by retrieving other bean objects through the BeanFactory object. This is certainly not recommended, and DI is recommended for injecting dependent bean objects. BeanFactoryAware is a factoryAware interface.

package org.springframework.beans.factory; import org.springframework.beans.BeansException; Public interface BeanFactoryAware extends Aware {// After the bean property is filled, However, call the method void setBeanFactory(BeanFactory) throws BeansException before the initial callback (such as afterPropertiesSet() method). }Copy the code

The test code and unit test verify the results as follows:

package com.chenpi; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.stereotype.Component; /** * @author * @version 1.0 * @description * @date 2022/4/3 */ @component public class Person implements BeanNameAware, BeanFactoryAware { private String beanName; private BeanFactory beanFactory; @Override public void setBeanName(String name) { this.beanName = name; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public String getBeanName() { return beanName; } public BeanFactory getBeanFactory() { return beanFactory; }}Copy the code
package com.chenpi; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class ApplicationTests { @Autowired private Person person; @Test public void testValue() { System.out.println("Person BeanName:" + person.getBeanName()); System.out.println("Person Bean's BeanFactory:" + person.getBeanFactory().getClass()); System.out.println( person == person.getBeanFactory().getBean(person.getBeanName(), Person.class)); Person BeanName: Person Person Bean's BeanFactory:class org.springframework.beans.factory.support.DefaultListableBeanFactory trueCopy the code

ApplicationContextAware interface

The ApplicationContextAware interface can be implemented if the Spring Bean needs to be aware of the Spring container, the ApplicationContext object. Other Bean objects can be obtained through the Spring container for collaboration.

Of course, if a bean object need to access the file resources, such as call applicationContext. GetResource () method, Or want to release an application event applicationContext. PublishEvent (ApplicationEvent event), or need to access the MessageSource, this way can be realized. Officials for these particular scenario, however, best to achieve more specific ResourceLoaderAware, ApplicationEventPublisherAware or MessageSourceAware interface is more appropriate.

package org.springframework.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;

public interface ApplicationContextAware extends Aware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
Copy the code

The test code and unit test verify the results as follows:

package com.chenpi; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author * @version 1.0 * @description * @date 2022/4/3 */ @component public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware { private String beanName; private BeanFactory beanFactory; private ApplicationContext applicationContext; @Override public void setBeanName(String name) { this.beanName = name; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public String getBeanName() { return beanName; } public BeanFactory getBeanFactory() { return beanFactory; } public ApplicationContext getApplicationContext() { return applicationContext; }}Copy the code
package com.chenpi; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; @SpringBootTest class ApplicationTests { @Autowired private Person person; @Test public void testValue() { System.out.println("Person BeanName:" + person.getBeanName()); System.out.println("Person Bean's BeanFactory:" + person.getBeanFactory().getClass()); System.out.println( person == person.getBeanFactory().getBean(person.getBeanName(), Person.class)); ApplicationContext applicationContext = person.getApplicationContext(); Person person1 = applicationContext.getBean(person.getBeanName(), Person.class); System.out.println(applicationContext.getClass()); System.out.println(person == person1); Person BeanName: Person Person Bean's BeanFactory:class org.springframework.beans.factory.support.DefaultListableBeanFactory true class org.springframework.web.context.support.GenericWebApplicationContext trueCopy the code

Click to follow, the first time to learn about Huawei cloud fresh technology ~