Spring Aware接口解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Aware接口解析相关的知识,希望对你有一定的参考价值。

参考技术A Spring的依赖注入的最大亮点是所有的Bean对Spring容器的存在是没有意识的,我们可以将Spring容器换成其他的容器,Spring容器中的Bean的耦合度因此也是极低的。
但是我们在实际的开发中,我们却经常要用到Spring容器本身的功能资源,所以Spring容器中的Bean此时就要意识到Spring容器的存在才能调用Spring所提供的资源。我们通过Spring提供的一系列接口Spring Aware来实现具体的功能。

Aware是一个具有标识作用的超级接口,实现该接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通过回调。也就是说:直接或间接实现了这个接口的类,都具有被spring容器通知的能力。

Spring Aware的目的是为了让Bean获得Spring容器的服务。因为ApplicationContext接口集成了MessageSource接口、ApplicationEventPublisher接口和ResourceLoader接口,因此当Bean继承自ApplicationContextAware的时候就可以得到Spring容器的所有服务。

实现 ApplicationContextAware 接口的Plane.java

参考Light.java

这两个都是在后置处理器ApplicationContextAwareProcessor中进行回调函数调用的。

Spring - BeanFactoryAware扩展接口

文章目录


Pre

Spring Boot - 扩展接口一览


org.springframework.beans.factory.BeanFactoryAware

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;

/**
 * Interface to be implemented by beans that wish to be aware of their
 * owning @link BeanFactory.
 *
 * <p>For example, beans can look up collaborating beans via the factory
 * (Dependency Lookup). Note that most beans will choose to receive references
 * to collaborating beans via corresponding bean properties or constructor
 * arguments (Dependency Injection).
 *
 * <p>For a list of all bean lifecycle methods, see the
 * @link BeanFactory BeanFactory javadocs.
 *
 * @author Rod Johnson
 * @author Chris Beams
 * @since 11.03.2003
 * @see BeanNameAware
 * @see BeanClassLoaderAware
 * @see InitializingBean
 * @see org.springframework.context.ApplicationContextAware
 */
public interface BeanFactoryAware extends Aware 

	/**
	 * Callback that supplies the owning factory to a bean instance.
	 * <p>Invoked after the population of normal bean properties
	 * but before an initialization callback such as
	 * @link InitializingBean#afterPropertiesSet() or a custom init-method.
	 * @param beanFactory owning BeanFactory (never @code null).
	 * The bean can immediately call methods on the factory.
	 * @throws BeansException in case of initialization errors
	 * @see BeanInitializationException
	 */
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;



扩展点说明

扩展点方法为setBeanFactory,可以拿到BeanFactory这个属性。

使用场景:可以在bean实例化之后,但还未初始化之前,拿到 BeanFactory,在这个时候,可以对每个bean进行特殊化的定制。也或者可以把BeanFactory拿到进行缓存,日后使用。


Aware接口

  • Spring core 和 context的内建Aware接口
ApplicationEventPublisherAware
MessageSourceAware
ResourceLoaderAware
BeanFactoryAware
EnvironmentAware
EmbeddedValueResolverAware
ImportAware
LoadTimeWeaverAware
BeanClassLoaderAware
BeanNameAware
ApplicationContextAware
  • Spring web内建的Aware接口
ServletContextAware
ServletConfigAware
  • Spring其它内建Aware接口
SchedulerContextAware (spring scheduling)
NotificationPublisherAware (spring jmx export)
BootstrapContextAware (spring jca)

Spring内建Aware接口的执行时机及顺序

Aware接口的执行时机肯定是在Spring Bean创建的时候。

对于Aware接口的执行实现主要有一下两种模式

  • 初始化Bean(initializeBean)的时候直接进行方法调用 -> setXXXX
  • BeanPostProcessor -> Object postProcessBeforeInitialization(Object bean, String beanName)

processor.postProcessBeforeInitialization(result, beanName);

进入到

Spring内置的核心Aware BeanPostProcessor是ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization

我们继续看下 invokeAwareInterfaces(bean);

可知ApplicationContextAwareProcessor关联了大部分Spring内置Aware接口,它们的执行顺序如下:

EnvironmentAware -> EmbeddedValueResolverAware -> ResourceLoaderAware -> ApplicationEventPublisherAware -> MessageSourceAware ->   ApplicationStartupAware -> ApplicationContextAware

结论: 直接方法调用的时机要早于通过BeanPostProcessor#postProcessBeforeInitialization调用的时机

由于Aware的接口的调用受到BeanPostProcessor的直接影响,因此BeanPostProcessor的执行顺序也就是Aware接口的调用顺序。


那刚才为啥直接跳到了 ApplicationContextAwareProcessor

我们看看可以看看ApplicationContextAwareProcessor的设置执行时机

AbstractApplicationContext#refresh方法

public void refresh() throws BeansException, IllegalStateException 
        synchronized (this.startupShutdownMonitor) 
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

      //....省略其余代码



继续看 prepareBeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) 
        //....省略其余代码
        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

      //....省略其余代码

可以看到 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)这里可以看到ApplicationContextAwareProcessor直接第一个加入到该BeanFactory中。


源码解析 (直接调用)

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
	BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		org.springframework.beans.factory.support.AbstractBeanFactory#getBean
		  org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean	
			  org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
					org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
						 

doCreateBean方法中

重点看

	// Initialize the bean instance.
		Object exposedObject = bean;
		try 
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		

进入 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean

if (System.getSecurityManager() != null) 
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> 
				invokeAwareMethods(beanName, bean);
				return null;
			, getAccessControlContext());
		
		else 
			invokeAwareMethods(beanName, bean);
		

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(String beanName, 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);
			
		
	

看到了吧

if (bean instanceof BeanFactoryAware) 
		((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);

由以上代码片段可以得出结论:Aware接口执行顺序是

 BeanNameAware -> BeanClassLoaderAware -> BeanFactoryAware

调用链如下

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
	BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		org.springframework.beans.factory.support.AbstractBeanFactory#getBean
		  org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean	
			  org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
					org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
						 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
								org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods

源码分析 (BeanPostProcessor调用执行顺序)

其实上面最开始的截图里已经有了,我们再看下

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
	BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		org.springframework.beans.factory.support.AbstractBeanFactory#getBean
		  org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean	
			  org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
					org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
						 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean

继续 initializeBean

//....省略
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) 
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

 //....省略

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
  throws BeansException 

  Object result = existingBean;
  for (BeanPostProcessor processor : getBeanPostProcessors()) 
    Object current = processor.postProcessBeforeInitialization(result, beanName);
    if (current == null) 
      return result;
    
    result = current;
  
  return result;


public List<BeanPostProcessor> getBeanPostProcessors() 
  return this.beanPostProcessors;


private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

可知beanPostProcessors是关联该BeanFactory的有序列表, 这个列表的数据来源就是ConfigurableBeanFactory#addBeanPostProcessor(BeanPostProcessor beanPostProcessor) 这个方法。

回到AbstractApplicationContext#refresh()中的

registerBeanPostProcessors(beanFactory);//向BeanFactory注入BeanPost

注册BeanPostProcessor的最终执行者是PostProcessorRegistrationDelegate.registerBeanPostProcessors

这其中的排序规则如下(针对于属于该BeanFactoryBeanPostProcessor BeanDefinition):

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
  • 实现了PriorityOrdered接口优先级最高, 再按order进行排序 小 -> 大
  • 其次是实现了Ordered接口, 再按order进行排序 小 -> 大
  • 其它的根据BeanDefinition Spring注册顺序来

当然还可以通过BeanFactoryPostProcessor来配置该BeanFactory, 举个例子ConfigurationClassPostProcessor

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
  int factoryId = System.identityHashCode(beanFactory);
  if (this.factoriesPostProcessed.contains(factoryId)) 
    throw new IllegalStateException(
      "postProcessBeanFactory already called on this post-processor against " + beanFactory);
  
  this.factoriesPostProcessed.add(factoryId);
  if (!this.registriesPostProcessed.contains(factoryId)) 
    // BeanDefinitionRegistryPostProcessor hook apparently not supported...
    // Simply call processConfigurationClasses lazily at this point then.
    processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
  

  enhanceConfigurationClasses(beanFactory);
  //注册添加ImportAware接口处理器
  beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));




private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter 

    ....

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) 
    if (bean instanceof ImportAware) 
      ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
      AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
      if (importingClass != null) 
        //ImportAware#setImportMetadata调用
        ((ImportAware) bean).setImportMetadata(importingClass);
      
    
    return bean;
  

由以上可知ImportAware执行顺序ApplicationContextAwareProcessor关联的那些Aware接口之后执行。


其实还有一个 LoadTimeWeaverAwareProcessor

AbstractApplicationContext#prepareBeanFactory
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) //有条件的注入, 必须存在该bean或者bean definition
  beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  // Set a temporary ClassLoader for type matching.
  beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));

目前的Aware接口执行顺序如下:

BeanNameAware -> BeanClassLoaderAware -> BeanFactoryAware -> EnvironmentAware -> EmbeddedValueResolverAware -> ResourceLoaderAware -> ApplicationEventPublisherAware -> MessageSourceAware -> ApplicationContextAware -> ImportAware -> LoadTimeWeaverAware

扩展点示例

package com.artisan.bootspringextend.testextends;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.annotation.Configuration;

/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/12/4 9:53
 * @mark: show me the code , change the world
 */

@Slf4j
@Configuration
public class ExtendBeanFactoryAware implements BeanFactoryAware 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException 
        log.info("----->ExtendBeanFactoryAware  " , beanFactory.getBean(ExtendBeanFactoryAware.class).getClass().getSimpleName());
    

    

再看第二个比较全的扩展

 package com.artisan.bootspringextend.testextends;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.*;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/12/4 11:02
 * @mark: show me the code , change the world
 */
@Slf4j
@Component
public class ExtendInvokeAware implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware,
        ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,ApplicationStartupAware, ApplicationContextAware, ImportAware,
        LoadTimeWeaverAware 

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) 
        log.info(" ------> BeanClassLoaderAware::setBeanClassLoader invoked");
    

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException 
        log.info(" ------> BeanFactoryAware::setBeanFactory invoked");
    

    @Override
    public void setBeanName(String s) 
        log.info(" ------> BeanNameAware::setBeanName invoked");
    

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
        log.info(" ------> ApplicationContextAware::setApplicationContext invoked");
    

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) 
        log.info(" ------> ApplicationEventPublisherAware::setApplicationEventPublisher invoked");
    

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) 
        log以上是关于Spring Aware接口解析的主要内容,如果未能解决你的问题,请参考以下文章

Spring - BeanFactoryAware扩展接口

Spring - BeanFactoryAware扩展接口

spring中aware接口的

spring中的aware接口

Spring Aware接口详解

Spring的感知能力 Aware