执行BeanFactoryPostProcessor处理器
前面讲的是先处理BeanDefinitionRegistryPostProcessor接口的方法,处理完了之后现在要开始处理BeanFactoryPostProcessor接口的方法了,也是先BeanDefinitionRegistryPostProcessor
类型处理,然后是自定义的BeanFactoryPostProcessor
类型的处理。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);//BeanDefinitionRegistryPostProcessor的
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);//自定义的BeanFactoryPostProcessor
执行BeanDefinitionRegistryPostProcessor类型的处理器
主要就是ConfigurationClassPostProcessor
的postProcessBeanFactory
,还有就是自定义的,我们主要关注ConfigurationClassPostProcessor
的。
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
ConfigurationClassPostProcessor的postProcessBeanFactory
主要是做配置类的增强,然后添加一个ImportAwareBeanPostProcessor
后置处理器。
@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);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));//添加后置处理器
}
ConfigurationClassPostProcessor的enhanceConfigurationClasses提取出配置bean定义
首先会先把配置bean
定义都获取出来,根据ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE
属性,如果是配置类会设置属性full
或者lite
。这里要注意,如果前面有自定义的BeanDefinitionRegistryPostProcessor
扩展被创建出来的话,也会创建配置类,这里就会有个提示。
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);//获取配置属性
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {//bean注解的方法设置类加载器
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}//这里就是前面的full 跟 lite的用处了,full可以做增强
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}//已经存在单例了,就不能增强了
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {//没有要增强的配置bean直接返回
// nothing to enhance -> return immediately
return;
}
ConfigurationClassPostProcessor的enhanceConfigurationClasses进行增强
先创建一个配置类增强器ConfigurationClassEnhancer
,会遍历配置bean
定义,获取代理的目标类,然后进行代理增强,返回代理类,然后把bean
定义的BeanClass
设置为代理类,这样后面创建的时候就会创建代理类。
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class设置代理目标类属性
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();//获取代理的目标类
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);//进行代理
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);//设置为CGLIB动态代理后的类
}
}
ConfigurationClassEnhancer 的enhancer增强
先判断目标类是不是EnhancedConfiguration
类型的,如果是的话说明已经增强过了,因为spring
用CGLIB
增强的时候会继承目标类,实现EnhancedConfiguration
接口,其实就是BeanFactoryAware
接口。如果没有增强过就newEnhancer
创建一个增强器,然后createClass
创建增强类。
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {//如果已经是EnhancedConfiguration,已经被代理过了
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));//进行动态代理
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
ConfigurationClassEnhancer的newEnhancer创建增强器
这个就是CGLIB
的增强器,要设置父类,设置接口,也就是EnhancedConfiguration
,然后设置生成策略,设置过滤器。
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);//设置父类
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});//设置要实现的接口,就是BeanFactoryAware
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));//生成策略
enhancer.setCallbackFilter(CALLBACK_FILTER);//过滤器拦截器
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());//过滤器类型
return enhancer;
}
CALLBACK_FILTER过滤器
其实就是一些拦截器,用来对方法做拦截,从而进行增强。
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
BeanFactoryAwareGeneratorStrategy生成策略
就是如何生成字节码文件,看自己对生成的代理类做扩展,比如他这个就是会生成一个属性$$beanFactory
,然后在方法拦截器里面进行使用。
其实就是让spring
的beanFactory
参与配置类的方法执行过程,具体后面会说这个有什么用。
ConfigurationClassEnhancer的createClass创建代理类
先创建代理类,而不创建实例,然后注册过滤器,里面是CGLIB
产生字节码的过程比较复杂。
private Class<?> createClass(Enhancer enhancer) {
Class<?> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);//注册回调
return subclass;
}
我们可以看到中间有个过程他生成了beanFactory
属性的字节码:
后面弄一篇我们自己来模拟下spring
怎么用cglib
生成动态代理的吧。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。