Spring Bean的后置处理器扩展接口
1. BeanPostProcessor
都是在目标对象被实例化之后,并且属性也被设置之后调用的
- postProcessBeforeInitialization
- 在afterPropertiesSet或者自定义的初始化方法(使用@bean注解中的initMethod()属性或者使用xml配置)之前执行
- postProcessAfterInitialization
- 在afterPropertiesSet或者自定义的初始化方法之后执行(如果是从FactoryBean中获取的对象,则只有这个方法会起作用,,postProcessBeforeInitialization以及afterPropertiesSet或者自定义的初始化方法都不会有作用)
2. InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()方法的Object bean = resolveBeforeInstantiation(beanName, mbdToUse);方法里面执行了这个后置处理器
- postProcessBeforeInstantiation
- 在目标对象实例化之前调用,方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(一般都是代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
- postProcessAfterInstantiation
- 方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。如果该方法返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值。
- postProcessPropertyValues
- 方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内对属性值进行修改
- postProcessBeforeInitialization&postProcessAfterInitialization
- 父接口BeanPostProcessor的2个方法
3. SmartInstantiationAwareBeanPostProcessor
智能实例化Bean后置处理器(继承InstantiationAwareBeanPostProcessor)
- determineCandidateConstructors
- 检测Bean的构造器,可以检测出多个候选构造器(Java好像只会确定唯一的备选的构造器)
- getEarlyBeanReference
- 循环引用的后置处理器,这个东西比较复杂, 获得提前暴露的bean引用。主要用于解决循环引用的问题,只有单例对象才会调用此方法
- predictBeanType
- 预测bean的类型,在最后的类型转化时会用到
4. MergedBeanDefinitionPostProcessor
- postProcessMergedBeanDefinition
- 缓存bean的注入信息的后置处理器,仅仅是缓存或者干脆叫做查找更加合适,没有完成注入,注入是另外一个后置处理器的作用(不实现这个方法,也能直接调用postProcessPropertyValues完成属性值的注入)
5. DestructionAwareBeanPostProcessor
-
postProcessBeforeDestruction
- 在bean实例被销毁之前被调用
Spring Bean的扩展方法执行顺序
-
实例化前:
-
InstantiationAwareBeanPostProcessor:postProcessBeforeInstantiation
-
AbstractAutowireCapableBeanFactory# createBean ... Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
-
-
实例化:
-
SmartInstantiationAwareBeanPostProcessor:determineCandidateConstructors
-
AbstractAutowireCapableBeanFactory# createBeanInstance ... Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
-
-
属性赋值准备:
-
MergedBeanDefinitionPostProcessor:postProcessMergedBeanDefinition
-
AbstractAutowireCapableBeanFactory# doCreateBean ... applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
-
-
属性赋值之前:
-
InstantiationAwareBeanPostProcessor:postProcessAfterInstantiation
-
AbstractAutowireCapableBeanFactory# doCreateBean ... populateBean(beanName, mbd, instanceWrapper);
-
-
属性赋值:
-
InstantiationAwareBeanPostProcessor:postProcessPropertyValues
-
AbstractAutowireCapableBeanFactory# doCreateBean ... populateBean(beanName, mbd, instanceWrapper);
-
-
初始化前:
-
BeanPostProcessor:postProcessBeforeInitialization
-
AbstractAutowireCapableBeanFactory# doCreateBean ... exposedObject = initializeBean(beanName, exposedObject, mbd); wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
-
-
初始化:
- invokeInitMethods
AbstractAutowireCapableBeanFactory# doCreateBean ... exposedObject = initializeBean(beanName, exposedObject, mbd); invokeInitMethods(beanName, wrappedBean, mbd); -
初始化后:
- BeanPostProcessor:postProcessAfterInitialization
AbstractAutowireCapableBeanFactory# doCreateBean ... exposedObject = initializeBean(beanName, exposedObject, mbd); wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
Spring内部的后置处理器
内置BeanPostProcessor的加入时机
AnnotationConfigApplicationContext
-
在实例化时,会注册6个Sprint内部的BeanDefinition, 里面包含了一个BeanFactory的后置处理器BeanFactoryPostProcessor(ConfigurationClassPostProcessor),三个bean的后置处理器BeanPostProcessor(AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor),但这时这三个类并没有加入到BeanPostProcessor的列表中,只是加入到Spring容器中
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { // Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }- org.springframework.context.annotation.ConfigurationClassPostProcessor
- org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
- org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
- org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
- org.springframework.context.event.internalEventListenerProcessor
- org.springframework.context.event.DefaultEventListenerFactory
-
AnnotationConfigApplicationContext在refresh()的*prepareBeanFactory()*方法中会加入两个内置的BeanPostProcessor:
- org.springframework.context.support*.ApplicationContextAwareProcessor*
- org.springframework.context.support.ApplicationListenerDetector
-
AnnotationConfigApplicationContext在refresh()的invokeBeanFactoryPostProcessors(beanFactory)方法中会调用容器所有的BeanFactoryPostProcessor接口的方法,在其内部实现类ConfigurationClassPostProcessor会主动注册一个BeanPostProcessor:
- org.springframework.context.annotation.ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor
-
AnnotationConfigApplicationContext在*refresh()的registerBeanPostProcessors()*方法中中会主动从beanDefinitionMap中寻找BeanPostProcessors类型的bean,并进行注册,这个方法中如果没有开启额外的配置,会注入5个Spring内部的BeanPostProcessors:
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { ... }一个是在方法最开始,默认加入的:
- org.springframework.context.support.PostProcessorRegistrationDelegate.BeanPostProcessorChecker
三个bean是之前在AnnotationConfigApplicationContext初始化时,加入到Spring容器中的:
- org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
- org.springframework.beans.factory.annotation*.AutowiredAnnotationBeanPostProcessor*
- org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
一个是默认加入的(这个在prepareBeanFactory方法中已经加入过一次,重新加入,是为了将这个后置处理器放到整个后置处理器的最末端)
- org.springframework.context.support.ApplicationListenerDetector
BeanPostProcessor的执行顺序
BeanPostProcessor的执行顺序,是按照BeanPostProcessor的实现类加入到BeanFactory的List beanPostProcessors列表里面的顺序。(beanFactory.addBeanPostProcessor(postProcessor)方法默认是先移除,后添加,保证后面重新添加的实现类只有一个,且放在列表的最后面)依次为:
-
ApplicationContextAwareProcessor
-
ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor
-
PostProcessorRegistrationDelegate.BeanPostProcessorChecker
-
Spring内部扫描出来的BeanPostProcessor按照 priority > ordered > non 的顺序进行排列,但是在如果这个类实现了MergedBeanDefinitionPostProcessor接口,则会全部单独放在最后重新处理(就是MergedBeanDefinitionPostProcessor接口的实现类默认是属于Spring的内部类,会放在其他BeanPostProcessor接口实现类的后面执行)。Spirng内部处理时会分成四种类型priorityOrdered、 ordered以、noOrder以及internalPostProcessors(实现了MergedBeanDefinitionPostProcessor接口)进行分组处理。PriorityOrdered、 ordered以及noOrder只按有没有实现实现PriorityOrdered、 Ordered接口来划分,如果只是添加了@Priority或者@order注解,则不会被处理,还是会被分配到noOrder组里,而这个组最后并不会进行排序的操作,所以会出现顺序与注解值不匹配的情况。但是如果添加了@Priority或者@order注解,并且实现了MergedBeanDefinitionPostProcessor接口,则会按照注解以及接口中的顺序进行统一的排序,因为排序的实现类是AnnotationAwareOrderComparator,会读取接口以及注解中的信息。
Spring内部的三个类都实现了MergedBeanDefinitionPostProcessor接口,优先级顺序如下:
- CommonAnnotationBeanPostProcessor:PriorityOrdered(Ordered.LOWEST_PRECEDENCE - 3)
- AutowiredAnnotationBeanPostProcessor:PriorityOrdered(Ordered.LOWEST_PRECEDENCE - 2)
- RequiredAnnotationBeanPostProcessor: PriorityOrdered(Ordered.LOWEST_PRECEDENCE - 1)
-
ApplicationListenerDetector:默认放在最后
ApplicationContextAwareProcessor
主要实现了BeanPostProcessor接口的postProcessBeforeInitialization的方法
-
在postProcessBeforeInitialization的方法中处理Aware子类的注入(通过相对应的set方法进行注入),包括EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、AbstractApplicationContex
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; ... if (acc != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareInterfaces(bean); return null; }, acc); } else { invokeAwareInterfaces(bean); } return bean; } -
这个后置处理器是在AbstractApplicationContext类的refresh()中的prepareBeanFactory(beanFactory)子方法由框架自动加入的。
/** * * 配置其标准的特征,比如上下文的加载器ClassLoader和post-processors回调 * Configure the factory's standard context characteristics, * such as the context's ClassLoader and post-processors. * @param beanFactory the BeanFactory to configure * 此处的beanFactory参数等于DefaultListableFactory */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); //bean表达式解释器,后面说 能够获取bean当中的属性在前台页面 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //对象与string类型的转换 <property red="dao"> beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. //添加一个后置管理器 //ApplicationContextAwareProcessor // 能够在bean中获得到各种*Aware(*Aware都有其作用) beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); ... }
ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor
-
在postProcessBeforeInitialization的实现方法中会处理ImportAware类型的类,会为该类型的类注入引入类注解相关的元数据信息
@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(bean.getClass().getSuperclass().getName()); if (importingClass != null) { ((ImportAware) bean).setImportMetadata(importingClass); } } return bean; } } -
比较典型的应用是与redis缓存相关的RedisHttpSessionConfiguration类,该类会由@EnableRedisHttpSession注解引入到Spring容器中,通过这个后置处理器就可以获取当时添加@EnableRedisHttpSession注解这个类添加时所有注解的信息
@Configuration @ComponentScan("cn.gov.zcy.paas.web.auth.interceptor") @EnableScheduling @EnableRedisHttpSession(cleanupCron = "0 0 3 31 1 ?") public class MvcInterceptorAutoConfiguration extends WebMvcConfigurerAdapter { ... }
CommonAnnotationBeanPostProcessor
实现了InstantiationAwareBeanPostProcessor接口
-
是AnnotationConfigApplicationContext初始化时注入的6个内部bean之一
-
主要处理*@Resource、@PostConstruct和@PreDestroy*注解的实现,@Resource的处理是由他自己完成,@PostConstruct和@PreDestroy这两个是由他的父类 InitDestroyAnnotationBeanPostProcessor完成
-
在postProcessMergedBeanDefinition方法中,其父类InitDestroyAnnotationBeanPostProcessor会寻找@PostConstruct和@PreDestroy注解,他本身会寻找@Resource注解
CommonAnnotationBeanPostProcessor @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { // 父类处理@PostConstruct和@PreDestroy注解 super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); // 处理@Resource注解 InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); } InitDestroyAnnotationBeanPostProcessor @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { //找出被@PostConstruct和@PreDestroy注解修饰的方法 LifecycleMetadata metadata = findLifecycleMetadata(beanType); // 去除重复,并注册到beanDefinition中 metadata.checkConfigMembers(beanDefinition); } -
@PostConstruct注解的方法会在InitDestroyAnnotationBeanPostProcessor类的postProcessBeforeInitialization中进行调用处理,@PreDestroy注解的方法会在InitDestroyAnnotationBeanPostProcessor类的postProcessBeforeDestruction中进行调用
InitDestroyAnnotationBeanPostProcessor @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { metadata.invokeInitMethods(bean, beanName); } ... return bean; } @Override public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { metadata.invokeDestroyMethods(bean, beanName); } ... } -
@Resource注解是在CommonAnnotationBeanPostProcessor方法的 postProcessPropertyValues方法进行注入的,底层的方法和@Autowired基本相同,都是调用InjectionMetadata的inject方法进行注入
- @Resource是Java JSR-250中引入的注解,默认是按照byName进行注入,也支持byType。@Resource里面两个属性namey以及type分别对应两种方式。@Resource注解在进行注入操作时,会先判断Spring容器中(singletonObjects和beanDefinitionNames)是不是存在对应的beanName,如果存在就会直接使用factory.getBean方法获取同名的bean进行注入,如果不存在,底层会使用@Autowired相同的方法,去按照先ByType,然后ByName的方式注入。
- 使用@Resource注解也支持注入Map、list、以及Array等数据结构,但是要注意,注入这些类型时定义的名字一定要是Spring容器中(singletonObjects和beanDefinitionNames)不存在的名字,不然由于优先byName寻找,导致奇怪的问题(因为Java的泛型是假的泛型,所以转化时不会报错)
CommonAnnotationBeanPostProcessor @Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { //找出类中被@Resource注解的属性和方法 //else if (field.isAnnotationPresent(Resource.class)) InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; }
AutowiredAnnotationBeanPostProcessor
实现了SmartInstantiationAwareBeanPostProcessor,MergedBeanDefinitionPostProcessor接口
-
是AnnotationConfigApplicationContext初始化时注入的6个内部bean之一
-
处理自动装配的注解,@Autowired,@Value,@Inject(JSR-330的注解,功能和使用方法与@Autowired相同)
-
实现了SmartInstantiationAwareBeanPostProcessor接口的determineCandidateConstructors方法(不算上空实现,是Spring容器中唯一实现了该接口的类),确认选择用哪一个构造方法进行实例化bean,构造方法的选择主要是基于以下几点:
- 如果没有定义构造函数,则默认使用无参的构造函数
- 如果只有唯一一个默认函数,则使用唯一的构造函数
- 如果存在多个构造函数并且包含有@Autowird注解,则使用使用加了@Autowird注解的构造方法,如果有多个构造函数添加了@Autowird注解则会报错
- 如果存在多个构造函数并且都不带有@Autowird注解, 就默认使用无参的构造函数函数,不存在无参的构造函数时就会报错
通过这个方法选择的构造方法如果是Java代码最多只会有一个(Kotlin支持定义PrimaryConstructor,所以有可能会选出两个构造方法Primary+default,但是Java不支持定义PrimaryConstructor,所以最多只会有一个 )
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException { // 默认先尝试从缓存中获取 Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass); if (candidateConstructors == null) { // Fully synchronized resolution now... synchronized (this.candidateConstructorsCache) { candidateConstructors = this.candidateConstructorsCache.get(beanClass); if (candidateConstructors == null) { Constructor<?>[] rawCandidates; try { // 获取该类所有的构造方法 rawCandidates = beanClass.getDeclaredConstructors(); }catch... List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length); Constructor<?> requiredConstructor = null; Constructor<?> defaultConstructor = null; // 好像只有Kotlin的方式可以使用,java不支持 Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); int nonSyntheticConstructors = 0; for (Constructor<?> candidate : rawCandidates) { // Synthetic:由java编译器生成的(有synthetic标记的field和method是class内部使用的,正常的源代码里不会出现synthetic field) if (!candidate.isSynthetic()) { nonSyntheticConstructors++; } else if (primaryConstructor != null) { continue; } AnnotationAttributes ann = findAutowiredAnnotation(candidate); if (ann == null) { Class<?> userClass = ClassUtils.getUserClass(beanClass); if (userClass != beanClass) { try { Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes()); ann = findAutowiredAnnotation(superCtor); } catch (NoSuchMethodException ex) { // Simply proceed, no equivalent superclass constructor found... } } } if (ann != null) { if (requiredConstructor != null) { throw new BeanCreationException(beanName, "Invalid autowire-marked constructor: " + candidate + ". Found constructor with 'required' Autowired annotation already: " + requiredConstructor); } boolean required = determineRequiredStatus(ann); if (required) { if (!candidates.isEmpty()) { throw new BeanCreationException(beanName, "Invalid autowire-marked constructors: " + candidates + ". Found constructor with 'required' Autowired annotation: " + candidate); } requiredConstructor = candidate; } candidates.add(candidate); } else if (candidate.getParameterCount() == 0) { defaultConstructor = candidate; } } if (!candidates.isEmpty()) { // Add default constructor to list of optional constructors, as fallback. if (requiredConstructor == null) { if (defaultConstructor != null) { candidates.add(defaultConstructor); } else if (candidates.size() == 1 && logger.isWarnEnabled()) { logger.warn("Inconsistent constructor declaration on bean with name '" + beanName + "': single autowire-marked constructor flagged as optional - " + "this constructor is effectively required since there is no " + "default constructor to fall back to: " + candidates.get(0)); } } candidateConstructors = candidates.toArray(new Constructor<?>[0]); } else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { candidateConstructors = new Constructor<?>[] {rawCandidates[0]}; } else if (nonSyntheticConstructors == 2 && primaryConstructor != null && defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) { candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor}; } else if (nonSyntheticConstructors == 1 && primaryConstructor != null) { candidateConstructors = new Constructor<?>[] {primaryConstructor}; } else { candidateConstructors = new Constructor<?>[0]; } this.candidateConstructorsCache.put(beanClass, candidateConstructors); } } } return (candidateConstructors.length > 0 ? candidateConstructors : null); } -
postProcessMergedBeanDefinition方法寻找带有(@Autowired,@Value,@Inject)注解的bean,并缓存信息。会区分是属性注入还是方法注入,分别使用不同的对象封装(AutowiredFieldElement和AutowiredMethodElement)
-
postProcessPropertyValues方法,处理(@Autowired,@Value,@Inject)注解,实现属性的注入。AutowiredFieldElement和AutowiredMethodElement都重写了inject注入方法,会调用自己的。
- 支持处理一些复杂的bean,比如说List,Map,数组, Spring会帮你找出某一个接口所有的实现类,注入到List、map或者数组中(map默认的key是beanName)
- 注入首先根据byType进行寻找注入,如果根据type找到符合的class多余一个,就根据byName,决定注入。(如果没有匹配的就会根据@Autowired的required属性,决定是否直接抛错)
RequiredAnnotationBeanPostProcessor
主要实现了InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues方法
-
是AnnotationConfigApplicationContext初始化时注入的6个内部bean之一
-
处理@Required注解,做必填性校验,注解适用于 bean 属性的 setter 方法,并且它指示受影响的 bean 属性必须在XML配置文件中配置时被填充或者@autowired(@Resource...)在setter方法上,否则容器将抛出 BeanInitializationException 异常。
- 只要被处理过,就可以满足要求,不需要一定要注入属性。下面这段代码,如果Spring容器中没有ChenDao这个bean,注入时为null,但因为加了@Autowired(required = false)注解,启动时不会报错,只会在调用 hello()方法时会出现空指针;但是如果没有@Autowired(required = false)的注解,只有@Required注解,那么启动时就会报 BeanInitializationException 异常
public class ChenService{ @Required @Autowired(required = false) public void setChenDao(ChenDao chenDao) { this.chenDao = chenDao; } public void hello() { chenDao.hello(); } }
AnnotationAwareAspectJAutoProxyCreator
- 处理Aop