SpringBoot常用扩展接口整理

188 阅读19分钟

1、ApplicationContextInitializer

这是整个spring容器在刷新之前初始化ConfigurableApplicationContext的回调接口,简单来说,就是在容器刷新之前调用此类的initialize方法。这个点允许被用户自己扩展。用户可以在整个spring容器还没被初始化之前做一些事情。

可以想到的场景可能为,在最开始激活一些配置,或者利用这时候class还没被类加载器加载的时机,进行动态字节码注入等操作。

扩展方式为:

public class TestApplicationContextInitializer implements ApplicationContextInitializer {      
    @Override      
    public void initialize(ConfigurableApplicationContext applicationContext) {      
        System.out.println("[ApplicationContextInitializer]");      
    }      
}

要想TestApplicationContextInitializer的bean添加到容器中并生效,可以有以下几种方式:

  1. 在启动类中用springApplication.addInitializers(new TestApplicationContextInitializer())语句加入
  2. 配置文件配置context.initializer.classes=com.example.demo.TestApplicationContextInitializer
  3. 在spring.factories中加入org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

接下来我们看看ApplicationContextInitializer是如何被SpringBoot加载和调用的吧:

1、ApplicationContextInitializer的加载:

在SpringApplication类的构造函数中:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	..............
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
	.......
}

在getSpringFactoriesInstances中查找所有实现了ApplicationContextInitializer的bean,由于这个时候Spring的容器还没有初始化,容器中还没有bean对象,因此不能直接从容器中拿,而要从Spring.factories文件中查找定义的名称,然后实例化。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	//loadFactoryNames查找spring.factories文件中定义的beanName
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	...........
	try {
		Enumeration<URL> urls = (classLoader != null ?
		        //这里的FACTORIES_RESOURCE_LOCATION常量定义正是META-INF/spring.factories文件
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				List<String> factoryClassNames = Arrays.asList(
						StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
				result.addAll((String) entry.getKey(), factoryClassNames);
			}
		}
		cache.put(classLoader, result);
		return result;
	} catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

2、ApplicationContextInitializer的调用:

//SpringApplication.java文件

public ConfigurableApplicationContext run(String... args) {
  ..........
  prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  ..........
}

private void prepareContext(ConfigurableApplicationContext context,
		ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments, Banner printedBanner) {
	............
	applyInitializers(context);
	............
}

protected void applyInitializers(ConfigurableApplicationContext context) {
	for (ApplicationContextInitializer initializer : getInitializers()) {
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);		
		initializer.initialize(context);
	}
}

可以看到applyInitializers的实现正是遍历所有的ApplicationContextInitializer实现bean并调用其initialize方法;getInitializers方法正是读取的上一步中从spring.factories中定义的ApplicationContextInitializer。

2、BeanDefinitionRegistryPostProcessor

这个接口在读取项目中的beanDefinition之后执行,提供一个补充的扩展点。

使用场景:你可以在这里动态注册自己的beanDefinition,可以加载classpath之外的bean。

比如如下 demo:

public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("************[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("************[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");
    }
}

下面来看看BeanDefinitionRegistryPostProcessor在SpringBoot中是如何加载和执行的:

AbstractApplicationContext.java

public void refresh() {
  .........
  invokeBeanFactoryPostProcessors(beanFactory);
  .........
}

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
	............
}

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	...........
	//从beanFactory中加载出所有的BeanDefinitionRegistryPostProcessor定义
	List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
	for (String ppName : postProcessorNames) {
		currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
		processedBeans.add(ppName);
	}
	sortPostProcessors(currentRegistryProcessors, beanFactory);
	registryProcessors.addAll(currentRegistryProcessors);
	//循环遍历调用BeanDefinitionRegistryPostProcessor
	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
	//循环遍历调用BeanFactoryPostProcessor
	invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
	..........
}

private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    //循环遍历调用BeanDefinitionRegistryPostProcessor
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessBeanDefinitionRegistry(registry);
	}
}

private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    //循环遍历调用BeanFactoryPostProcessor
	for (BeanFactoryPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessBeanFactory(beanFactory);
	}
}

3、BeanFactoryPostProcessor

这个接口是beanFactory的扩展接口,调用时机在spring在读取beanDefinition信息之后,实例化bean之前。

在这个时机,用户可以通过实现这个扩展接口来自行处理一些东西,比如修改已经注册的beanDefinition的元信息。

比如如下demo:

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {      
    @Override      
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {      
        System.out.println("[BeanFactoryPostProcessor]");      
    }      
}

上面的BeanDefinitionRegistryPostProcessor接口是从这个接口继承过来的,在上面的AbstractApplicationContext.invokeBeanFactoryPostProcessors中先调用BeanDefinitionRegistryPostProcessor接口的bean,然后再调用BeanFactoryPostProcessor接口的bean。这两个接口的调用时机差不多,但是他们的偏重不一样:BeanDefinitionRegistryPostProcessor的时机是在这里动态注册自己的beanDefinition,可以加载classpath之外的bean,而BeanFactoryPostProcessor的时机是用户可以通过实现这个扩展接口来自行处理一些东西,比如修改已经注册的beanDefinition的元信息。

4、BeanPostProcessor

这个接口是在bean初始化的时候调用的,定义了两个方法,postProcessBeforeInitialization在实例化之前调用,postProcessAfterInitialization在初始化之后调用,这两个方法均可以在初始化之前或者之后改变bean的属性。

在SpringBoot中,其调用时机代码如下:

//AbstractAutowireCapableBeanFactory.java

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	...........
	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	invokeInitMethods(beanName, wrappedBean, mbd);
	
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}

从上面的代码中可以看到,invokeInitMethods调用bean的初始化方法,在初始化之前调用applyBeanPostProcessorsBeforeInitialization来完成对postProcessBeforeInitialization的调用,初始化之后调用applyBeanPostProcessorsAfterInitialization来完成对postProcessAfterInitialization的调用。

5、ApplicationContextAwareProcessor

这是一个类,实现了上面的BeanPostProcessor接口。该类本身并没有扩展点,但是该类内部却有6个扩展点可供实现 ,这些类触发的时机在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(this.embeddedValueResolver);
		}
		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);
		}
	}
}

可以看到,该类用于执行各种驱动接口,在bean实例化之后,属性填充之后,通过执行以上的扩展接口,来获取对应容器的变量。这六个扩展点是:

  1. EnvironmentAware:用于获取EnviromentAware的一个扩展类,这个变量非常有用, 可以获得系统内的所有参数。当然个人认为这个Aware没必要去扩展,因为spring内部都可以通过注入的方式来直接获得。
  2. EmbeddedValueResolverAware:用于获取StringValueResolver的一个扩展类, StringValueResolver用于获取基于String类型的properties的变量,一般我们都用@Value的方式去获取,如果实现了这个Aware接口,把StringValueResolver缓存起来,通过这个类去获取String类型的变量,效果是一样的。
  3. ResourceLoaderAware:用于获取ResourceLoader的一个扩展类,ResourceLoader可以用于获取classpath内所有的资源对象,可以扩展此类来拿到ResourceLoader对象。
  4. ApplicationEventPublisherAware:用于获取ApplicationEventPublisher的一个扩展类,ApplicationEventPublisher可以用来发布事件,结合ApplicationListener来共同使用,下文在介绍ApplicationListener时会详细提到。这个对象也可以通过spring注入的方式来获得。
  5. MessageSourceAware:用于获取MessageSource的一个扩展类,MessageSource主要用来做国际化。
  6. ApplicationContextAware:用来获取ApplicationContext的一个扩展类,ApplicationContext应该是很多人非常熟悉的一个类了,就是spring上下文管理器,可以手动的获取任何在spring上下文注册的bean,我们经常扩展这个接口来缓存spring上下文,包装成静态方法。同时ApplicationContext也实现了BeanFactory,MessageSource,ApplicationEventPublisher等接口,也可以用来做相关接口的事情。

6、InstantiationAwareBeanPostProcessor

该接口继承了BeanPostProcess接口,InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段。

该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段:实例化阶段和初始化阶段。

InstantiationAwareBeanPostProcessor接口的三个方法加上BeanPostProcess接口的两个方法,其调用顺序为:

  1. postProcessBeforeInstantiation:实例化bean之前,相当于new这个bean之前
  2. postProcessAfterInstantiation:实例化bean之后,相当于new这个bean之后
  3. postProcessPropertyValues:bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现
  4. postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前
  5. postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后

使用场景:这个扩展点非常有用 ,无论是写中间件和业务中,都能利用这个特性。比如对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行统一的设值等等。

postProcessBeforeInitialization和postProcessAfterInitialization在SpringBoot中的调用时机已经在上面的BeanPostProcess接口中介绍过了,接下来看看这个接口的几个方法在SpringBoot中的调用时机吧:

//AbstractBeanFactory.java
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) {
	.........
	return createBean(beanName, mbd, args);
	........
}

//AbstractAutowireCapableBeanFactory.java
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	..........
	//1、此处调用postProcessBeforeInstantiation
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
	.........
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);	
	return beanInstance;
	...........
}

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {		
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);				
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
	..........
	populateBean(beanName, mbd, instanceWrapper);
	//4、initializeBean中完成postProcessBeforeInitialization和postProcessAfterInitialization的调用
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	............		
}

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	...........
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			//2、此处调用postProcessAfterInstantiation
			if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
				continueWithPropertyPopulation = false;
				break;
			}
		}
	}
	..................
	if (hasInstAwareBpps || needsDepCheck) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				//3、此处调用postProcessPropertyValues
				pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
				if (pvs == null) {
					return;
				}
			}
		}		
	}

	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}
  1. 在createBean中首先完成对postProcessBeforeInstantiation的调用;
  2. 在createBean中接着调用doCreateBean,在doCreateBean中首先调用populateBean,在populateBean中首先调用postProcessAfterInstantiation;
  3. 在populateBean中接着调用postProcessPropertyValues;
  4. populateBean完成后返回到doCreateBean方法,最后调用initializeBean方法,这个方法完成对bean的初始化,也就是会调用postProcessBeforeInitialization和postProcessAfterInitialization。

7、SmartInstantiationAwareBeanPostProcessor

该扩展接口有3个触发点方法:

  1. predictBeanType:该触发点发生在postProcessBeforeInstantiation之前(在图上并没有标明,因为一般不太需要扩展这个点),这个方法用于预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。
  2. determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。
  3. getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

扩展demo如下:

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {      
      
    @Override      
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);      
        return beanClass;      
    }      
      
    @Override      
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);      
        return null;      
    }      
      
    @Override      
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);      
        return bean;      
    }      
}

8、BeanFactoryAware

这个类只有一个触发点,发生在bean的实例化并注入属性之后。

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

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

扩展demo如下:

public class TestBeanFactoryAware implements BeanFactoryAware {   
	private BeanFactory beanFactory;

    @Override      
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {      
    	this.beanFactory = beanFactory;
    }      
}   

在SpringBoot中,其调用时机如下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
	.........
	instanceWrapper = createBeanInstance(beanName, mbd, args);
	.........
	populateBean(beanName, mbd, instanceWrapper);
	//在这里完成BeanFactoryAware的调用
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	..........
}

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	//在这里完成BeanFactoryAware的调用
	invokeAwareMethods(beanName, bean);

	Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	invokeInitMethods(beanName, wrappedBean, mbd);
	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

	return wrappedBean;
}

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);
			}
		}
		//在这里完成BeanFactoryAware的调用
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

在doCreateBean中可以看到BeanFactoryAware的调用是在实例化bean之后并且注入属性之后;在initializeBean中可以看到BeanFactoryAware的调用的是在初始化之前就完成的。在invokeAwareMethods中将所有实现了BeanNameAware, BeanClassLoaderAware, BeanFactoryAware的接口实现都调用了一次。

9、BeanNameAware

可以看到,这个类也是Aware扩展的一种,触发点在bean的初始化之前,也就是postProcessBeforeInitialization之前,这个类的触发点方法只有一个:setBeanName。

使用场景为:用户可以扩展这个点,在初始化bean之前拿到spring容器中注册的的beanName,来自行修改这个beanName的值。

扩展demo如下:

public class NormalBeanA implements BeanNameAware{        
    @Override      
    public void setBeanName(String name) {      
        System.out.println("[BeanNameAware] " + name);      
    }      
}   

在SpringBoot中,在上面介绍到的BeanFactoryAware接口时,invokeAwareMethods方法里面首先就调用了所有实现了BeanNameAware接口的bean。

10、@PostConstruct

这个并不算一个扩展点,其实就是一个标注。其作用是在bean的初始化阶段,如果对一个方法标注了@PostConstruct,会先调用这个方法。这里重点是要关注下这个标准的触发点,这个触发点是在postProcessBeforeInitialization之后,InitializingBean.afterPropertiesSet之前。

使用场景:用户可以对某一方法进行标注,来进行初始化某一个属性。

1、PostConstruct标注方法的加载:

//AbstractAutowireCapableBeanFactory.java

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
	.........
	instanceWrapper = createBeanInstance(beanName, mbd, args);
	.........
	applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
	...........
	populateBean(beanName, mbd, instanceWrapper);
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	..............
}

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof MergedBeanDefinitionPostProcessor) {
			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}
}

由于InitDestroyAnnotationBeanPostProcessor类实现了MergedBeanDefinitionPostProcessor接口,因此会调用InitDestroyAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法。

//InitDestroyAnnotationBeanPostProcessor.java

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	LifecycleMetadata metadata = findLifecycleMetadata(beanType);
	metadata.checkConfigMembers(beanDefinition);
}

private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
	.............
	metadata = buildLifecycleMetadata(clazz);
	return metadata;
}

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
	............
	final LinkedList<LifecycleElement> currInitMethods = new LinkedList<>();
	ReflectionUtils.doWithLocalMethods(targetClass, method -> {
		//这里的initAnnotationType就是postConstructor注解
		if (initAnnotationType != null && method.isAnnotationPresent(initAnnotationType)) {
			LifecycleElement element = new LifecycleElement(method);
			//这里就是相当于把实现了postConstructor注解的方法保存到一个list中
			currInitMethods.add(element);			
		}
		...........
	});
	return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}

从上面可以看到,initAnnotationType指向的就是postConstructor注解,那么这个是在哪里指定的了?

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
		implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
		...........
		
		public CommonAnnotationBeanPostProcessor() {
            setOrder(Ordered.LOWEST_PRECEDENCE - 3);
            setInitAnnotationType(PostConstruct.class);
            setDestroyAnnotationType(PreDestroy.class);
            ignoreResourceType("javax.xml.ws.WebServiceContext");
        }
}

public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
	this.initAnnotationType = initAnnotationType;
}

CommonAnnotationBeanPostProcessor继承自InitDestroyAnnotationBeanPostProcessor类,在构造函数中就通过setInitAnnotationType(PostConstruct.class)指定了initAnnotationType指向的就是postConstructor注解。

2、SpringBoot调用PostConstruct标注方法的时机:

//AbstractAutowireCapableBeanFactory.java

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
	.........
	instanceWrapper = createBeanInstance(beanName, mbd, args);
	.........
	applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
	...........
	populateBean(beanName, mbd, instanceWrapper);
	//PostConstruct的时机在下面的方法中
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	..............
}

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	invokeAwareMethods(beanName, bean);

	//PostConstruct的时机在下面的方法中
	Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	invokeInitMethods(beanName, wrappedBean, mbd);
	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

	return wrappedBean;
}

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) {	
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		beanProcessor.postProcessBeforeInitialization(result, beanName);
	}
	..........
}

//InitDestroyAnnotationBeanPostProcessor.java

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
	metadata.invokeInitMethods(bean, beanName);
	return bean;
}

public void invokeInitMethods(Object target, String beanName) throws Throwable {
	............
	//这里的this.initMethods就是上一步中加载的所有定义了postConstructor注解的方法
	Collection<LifecycleElement> initMethodsToIterate = this.initMethods;			
	if (!initMethodsToIterate.isEmpty()) {		
		for (LifecycleElement element : initMethodsToIterate) {	
			//相当于调用了postConstructor注解标识的方法
			element.invoke(target);
		}
	}
}

可以看到postConstructor的时机是在创建bean的实例和注入bean的属性之后,刚处理完AWare接口的调用之后就开始调用postConstructor标注的方法。

调用完postConstructor方法之后再执行初始化。

11、InitializingBean

顾名思义,这个类是用来初始化bean的。InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。这个扩展点的触发时机在postProcessAfterInitialization之前。

使用场景:用户实现此接口,来进行系统启动的时候一些业务指标的初始化工作。

扩展demo:

public class NormalBeanA implements InitializingBean{      
    @Override      
    public void afterPropertiesSet() throws Exception {      
        System.out.println("[InitializingBean] NormalBeanA");      
    }      
} 

在SpringBoot中的调用时机:

//AbstractAutowireCapableBeanFactory.java

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
	.........
	instanceWrapper = createBeanInstance(beanName, mbd, args);
	.........
	applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
	...........
	populateBean(beanName, mbd, instanceWrapper);
	//InitializingBean的时机在下面的方法中
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	..............
}

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	invokeAwareMethods(beanName, bean);
	
	Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	//InitializingBean的时机在下面的方法中
	invokeInitMethods(beanName, wrappedBean, mbd);
	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

	return wrappedBean;
}

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	........
	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		//这里调用InitializingBean.afterPropertiesSet方法
		((InitializingBean) bean).afterPropertiesSet();
	}
	
	invokeCustomInitMethod(beanName, bean, mbd);
}

从上面可以看到,在调用InitializingBean.afterPropertiesSet之前,首先做了创建bean实例,注入属性,调用aware接口,在做完这些之后再调用InitializingBean.afterPropertiesSet方法,也就是说在afterPropertiesSet之前还没有调用bean的初始化方法,在这之后才开始调用bean的初始化方法以及调用postProcessAfterInitialization。

12、FactoryBean

这是一个工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式

使用场景:用户可以扩展这个类,来为要实例化的bean作一个代理,比如为该对象的所有的方法作一个拦截,在调用前后输出一行log,模仿ProxyFactoryBean的功能。

扩展Demo:

public class TestFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new TestObj(1, "zhangsan&lisi", "武汉市王八街", 45);
    }

    @Override
    public Class<?> getObjectType() {
        return TestObj.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

在SpringBoot中调用时机:

//AbstractAutowireCapableBeanFactory.java

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}
	
	Object object = null;
	if (mbd == null) {
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {		
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;	
        //FactoryBean调用走下面的方法
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	..........
	//首先从缓存中查找bean
	Object object = this.factoryBeanObjectCache.get(beanName);
	if (object == null) {
		//缓存中查找不到bean,那么就用FactoryBean来创建bean
		object = doGetObjectFromFactoryBean(factory, beanName);
	}
	..........
	return object;
}

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {
	//直接调用FactoryBean的getObject方法生成bean实例
	Object object = factory.getObject();
	............
	return object;
}

从上面的代码中可以看到,如果是非FactoryBean,则走普通bean创建的流程去创建,而如果是FactoryBean,则调用FactoryBean.getObject()来创建bean。

13、SmartInitializingSingleton

这个接口中只有一个方法afterSingletonsInstantiated,其作用是是 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization之后。

使用场景:用户可以扩展此接口在对所有单例对象初始化完毕后,做一些后置的业务处理。

扩展Demo:

public class TestSmartInitializingSingleton implements SmartInitializingSingleton {      
    @Override      
    public void afterSingletonsInstantiated() {      
        System.out.println("[TestSmartInitializingSingleton]");      
    }      
} 

在SpringBoot中的调用时机为:

public void refresh() throws BeansException, IllegalStateException {	
	prepareRefresh();	
	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
	prepareBeanFactory(beanFactory);
	postProcessBeanFactory(beanFactory);
	invokeBeanFactoryPostProcessors(beanFactory);
	registerBeanPostProcessors(beanFactory);
	initMessageSource();
	initApplicationEventMulticaster();
	onRefresh();
	registerListeners();
	//SmartInitializingSingleton的调用走这里
	finishBeanFactoryInitialization(beanFactory);	
	finishRefresh();
}

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {	
	beanFactory.setTempClassLoader(null);
	beanFactory.freezeConfiguration();
	//实例化所有的Singleton(单实例)的bean
	beanFactory.preInstantiateSingletons();
}

public void preInstantiateSingletons() throws BeansException {
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			//在这里先初始化单实例的bean
			getBean(beanName);
		}
	}
	
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			//这里判断单实例bean如果实现了SmartInitializingSingleton接口,则调用SmartInitializingSingleton接口
			smartSingleton.afterSingletonsInstantiated();
		}
	}
}

从上面的代码可以看出,SmartInitializingSingleton是在bean实例化之后才执行的。

14、CommandLineRunner

这个接口也只有一个方法:run(String... args),触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner,可以利用@Order来进行排序。

使用场景:用户扩展此接口,进行启动项目之后一些业务的预处理。

扩展demo为:

public class TestCommandLineRunner implements CommandLineRunner {      
      
    @Override      
    public void run(String... args) throws Exception {      
        System.out.println("[TestCommandLineRunner]");      
    }      
}

在SpringBoot中的调用时机为:

//我们的SpringBoot项目中都有这么一行代码
SpringApplication.run(Sprinbbootdemo1Application.class, args);

//SpringApplication.java

public ConfigurableApplicationContext run(String... args) {
	.............
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	............
	context = createApplicationContext();		
	prepareContext(context, environment, listeners, applicationArguments, printedBanner);
	refreshContext(context);
	afterRefresh(context, applicationArguments);		
	listeners.started(context);
	//这里开始调用runner
	callRunners(context, applicationArguments);
	listeners.running(context);
	
	return context;
}

private void callRunners(ApplicationContext context, ApplicationArguments args) {
	List<Object> runners = new ArrayList<>();
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	AnnotationAwareOrderComparator.sort(runners);
	for (Object runner : new LinkedHashSet<>(runners)) {
		//调用ApplicationRunner
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		//调用CommandLineRunner
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	}
}

private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
	(runner).run(args.getSourceArgs());
}

从上面的代码可以看出调用Runner是在Spring容器加载初始化全部完成后才执行的,也就是说这个时候容器里面的bean已经是全部加载完成且准备好了的。

从callRunners中可以看出SpringBoot支持两种类型的Runner:ApplicationRunner和CommandLineRunner。

15、DisposableBean

这个扩展点只有一个方法:destroy(),其触发时机为当此对象销毁时,会自动执行这个方法。比如说运行applicationContext.registerShutdownHook时,就会触发这个方法。

扩展Demo:

public class NormalBeanA implements DisposableBean {      
    @Override      
    public void destroy() throws Exception {      
        System.out.println("[DisposableBean] NormalBeanA");      
    }      
}

注意:

DisposableBean只在SpringBoot应用程序正常退出时才会去执行容器里面bean的Close方法,才会去调用DisposableBean的destroy方法,而非正常退出或者强制退出则不会调用。

正常退出SpringBoot应用程序的代码如下:

@Autowired
private ApplicationContext applicationContext;

@PostMapping("/stop")
public String stop() {
    // 加上自己的权限验证
    SpringApplication.exit(applicationContext);
    return "ok";
}

调用了SpringApplication.exit后,SpringBoot中流程是怎么运转的:

SpringApplication.exit(applicationContext);

//SpringApplication.java

public static int exit(ApplicationContext context, ExitCodeGenerator... exitCodeGenerators) {
	............
	close(context);
	...........
}

//AbstractApplicationContext.java

public void close() {
	doClose();
	Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}

protected void doClose() {
	publishEvent(new ContextClosedEvent(this));
	this.lifecycleProcessor.onClose();
	//这里关闭容器中所有的单实例bean
	destroyBeans();
	closeBeanFactory();
	onClose();
}

//DefaultSingletonBeanRegistry.java

public void destroySingletons() {
	.............
	String[] disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
	for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
		destroySingleton(disposableBeanNames[i]);
	}
	..............
}

public void destroySingleton(String beanName) {	
	removeSingleton(beanName);	
	DisposableBean disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
	//这里销毁Bean
	destroyBean(beanName, disposableBean);
}

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
	Set<String> dependencies = dependencies = this.dependentBeanMap.remove(beanName);
	for (String dependentBeanName : dependencies) {
		destroySingleton(dependentBeanName);
	}
	
	//这里会调用DisposableBean的destroy方法
	bean.destroy();
	
	Set<String> containedBeans = this.containedBeanMap.remove(beanName);
	for (String containedBeanName : containedBeans) {
		destroySingleton(containedBeanName);
	}
	
	..............
}

//DisposableBeanAdapter.java

public void destroy() {
	for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
		processor.postProcessBeforeDestruction(this.bean, this.beanName);
	}

	//这里会调用DisposableBean的destroy方法
	((DisposableBean) bean).destroy();

	if (this.destroyMethod != null) {
		invokeCustomDestroyMethod(this.destroyMethod);
	}
	else if (this.destroyMethodName != null) {
		Method methodToCall = determineDestroyMethod(this.destroyMethodName);
		if (methodToCall != null) {
			invokeCustomDestroyMethod(methodToCall);
		}
	}
}

可以看到在调用SpringApplication.close方法后,先发布ContextClosedEvent事件,然后调用destroyBeans销毁容器里面所有的bean,最后销毁容器。

在销毁bean时,先调用postProcessBeforeDestruction,然后调用DisposableBean.destroy方法,最后执行bean的destroyMethod所指定的方法。

16、ApplicationListener

准确的说,这个应该不算spring&springboot当中的一个扩展点,ApplicationListener可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。

但是spring内部也有一些内置事件,这种事件,可以穿插在启动调用中。我们也可以利用这个特性,来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情。

spring主要的内置事件有如下几个:

  1. ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用 refresh()方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
  2. ContextStartedEvent:当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。
  3. ContextStoppedEvent:当使用 ConfigurableApplicationContext接口中的 stop()停止ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。
  4. ContextClosedEvent:当使用 ConfigurableApplicationContext接口中的 close()方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。
  5. RequestHandledEvent:这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。