Giới thiệu
Một trong những nguyên tắc cốt lõi của Spring là IOC (Inversion of Control), và cách thực hiện IOC là DI (Dependency Injection). Khi một bean cần phụ thuộc vào một bean khác, bạn có thể sử dụng DI để tự động注入依赖的bean。但是,如果某个bean依赖的对象不是一个bean,通过容器的依赖注入就无法实现了。不过,Spring容器提供了扩展接口,当某个bean对某个对象感兴趣或者想要获取该对象时(比如想要获取Spring容器本身的资源),可以使用Aware接口来获取。
Aware接口
Aware接口是Aware系列接口的顶级接口,它没有任何定义,仅作为一个声明,用于标记实现了该接口的类会被Spring容器感知。具体需要感知什么内容由具体的子接口定义。
例如,如果想要获取BeanFactory对象,可以定义一个实现Aware接口的BeanFactoryAware接口;如果想要获取ApplicationContext对象,可以定义一个实现Aware接口的ApplicationContextAware接口。实现了对应接口的bean就可以获取到对应的对象。
每个Aware接口的子接口内部都需要有一个set方法,将相关对象设置进去,这样实现了该接口的类就可以获取到该对象。
Spring提供的常用Aware接口
Spring提供了许多自带的Aware子接口,主要用于获取Spring容器本身的对象。
1. BeanFactoryAware接口(获取BeanFactory对象)
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
2. ApplicationContextAware接口(获取ApplicationContext对象)
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
3. BeanNameAware接口(获取当前bean的beanName)
public interface BeanNameAware extends Aware {
void setBeanName(String name);
}
4. ApplicationEventPublisherAware接口(获取容器中的事件发布器,用于发布事件)
public interface ApplicationEventPublisherAware extends Aware {
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}
5. ResourceLoaderAware接口(获取资源加载器,用于获取外部资源文件)
public interface ResourceLoaderAware extends Aware {
void setResourceLoader(ResourceLoader resourceLoader);
}
每个Aware子接口都有一个共同点,即都有一个set方法用于设置该类型对象的方法。
Aware接口的使用
以Spring提供的Aware接口为例,自定义Bean分别实现Spring提供的Aware接口,测试案例如下:
public class MyAwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
private String beanName;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void test() {
System.out.println("beanName: " + beanName);
System.out.println("从BeanFactory中获取当前bean " + beanFactory.getBean(MyAwareBean.class).equals(this));
System.out.println("从ApplicationContext中获取当前bean " + applicationContext.getBean(MyAwareBean.class).equals(this));
}
}
自定义MyAwareBean对象,分别实现了BeanNameAware、BeanFactoryAware和ApplicationContextAware接口,调用test()方法测试结果如下:
beanName: myAwareBean
从BeanFactory中获取当前bean true
从ApplicationContext中获取当前bean true
既然bean可以通过实现BeanFactoryAware和ApplicationContextAware接口的方式注入Spring容器,那么bean获取其他bean的方式就可以通过容器直接获取,而不需要通过依赖注入来实现,例如以下案例:
public class MyAwareBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
private UserService userService;
private OrderService orderService;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.orderService = applicationContext.getBean(OrderService.class);
this.userService = applicationContext.getBean(UserService.class);
}
public void test() {
System.out.println(userService != null);
System.out.println(orderService != null);
}
}
MyAwareBean依赖UserService和OrderService,但没有采用依赖注入的方式,而是直接通过从Spring容器ApplicationContext中获取来设置赋值。
Aware接口的实现原理
当bean实现了Aware接口之后,在初始化过程中会执行Aware接口的方法。准确地说,是在bean填充属性之后,执行init方法之前。
具体执行逻辑在initializeBean方法中,bean的初始化过程分为三步:createBeanInstance(创建bean) -> populateBean(属性注入) -> initializeBean(执行初始化方法)。
Aware接口方法的执行就是在第三步initializeBean方法中,源码如下:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction从源码中可以看出,bean的初始化方法会先执行Aware接口的方法,然后再执行bean的具体初始化方法。因此,执行Aware接口的方法具体逻辑都在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) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这里分别判断bean是否实现了对应的Aware子接口,如果实现了Aware子接口,就将Bean转换成对应Aware子接口的对象,然后直接执行对应的set方法,将需要传入的参数传入即可。
但是这个方法只判断了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三个Aware接口,而Spring容器中还有很多其他的Aware接口的方法在这里并没有执行。其他接口如ApplicationContextAware等接口是通过后置处理器来执行的。
在initializeBean方法之后,会先执行bean的前置处理器方法,然后执行invokeInitMethods方法执行初始化逻辑,最后再执行bean的后置处理器方法。因此,bean初始化时会分别执行前置处理器和后置处理器方法,而执行Aware接口的处理器是ApplicationContextAwareProcessor,此处理器是在初始化ApplicationContext时加入的。
执行ApplicationContext初始化方法时会执行refresh()方法,而在refresh方法中第三步是预处理BeanFactory方法prepareBeanFactory(beanFactory),代码如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
}
在预处理BeanFactory时,会初始化ApplicationContextAwareProcessor对象,并将其添加到BeanFactory的处理器中。在初始化bean的时候,会遍历BeanFactory中的所有BeanPostProcessor,依次执行前置和后置方法。因此,这里执行Aware接口的方法需要在ApplicationContextAwareProcessor中查看,该类的源码如下:
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction可以看出在ApplicationContextAwareProcessor中的执行Aware接口的逻辑与BeanFactory初始化bean时的invokeAwareMethods方法逻辑基本相同,都是依次判断bean是否实现了Aware的各个子接口,实现了对应的接口就将bean转换成对应接口的对象,然后直接执行对应的set方法,而这一步是在invokeAwareMethods方法执行之后,bean的init方法执行之前操作的。
Tóm tắt
- Bean在initializeBean方法中执行逻辑为先执行invokeAwareMethods执行BeanFactory提供的Aware子接口。
- 然后遍历执行BeanFactory的后置处理器方法,其中ApplicationContextAwareProcessor处理器会执行ApplicationContext提供的Aware子接口方法。
- 执行完Aware子接口方法之后,才会继续执行bean的初始化方法。