@Configuration源码分析

https://blog.youkuaiyun.com/liman65727/article/details/105327300/
https://blog.youkuaiyun.com/liman65727/article/details/105460132

误区

错误理解❎:大家潜意识认为:
@Bean 不是在 @Configuration注解下面才能生效
同理@ComponentScan也不是非得在@Configuration注解下面也才能生效
让我们来揭开它神秘面纱

案例

// @Component
@Configuration
public class AppConfig {

    @Bean
    public TestBean testBean01() {
        return new TestBean();
    }

    @Bean
    public TestBean02 testBean02() {
        testBean01();//这里也会调用testBean方法。
        return new TestBean02();
    }

    public class TestBean {
        public TestBean() {
            System.err.println("TestBean.**************");
        }
    }

    public class TestBean02 {

    }

}

输出结果

当 @Component 存在时,TestBean.************** 打印一遍
当 @Configuration 存在时,TestBean.************** 打印一遍

分析

扫描@Configuration注解

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
image.png

	public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}

		AnnotationMetadata metadata;
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
					EventListenerFactory.class.isAssignableFrom(beanClass)) {
				return false;
			}
			metadata = AnnotationMetadata.introspect(beanClass);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " +
							className, ex);
				}
				return false;
			}
		}

		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			// 设置 full 
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		else if (config != null || isConfigurationCandidate(metadata)) {
            // 设置 lite
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}

		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		Integer order = getOrder(metadata);
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}

配置@Configuration类代理

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
image.png
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory
image.png

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		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 {
						abd.resolveBeanClass(this.beanClassLoader);
					}
					catch (Throwable ex) {
						throw new IllegalStateException(
								"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
					}
				}
			}

            // 这里判断是否包含 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()) {
			// nothing to enhance -> return immediately
			return;
		}

        // 给@Configuration 注解的类配置 cglib代理
		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()));
				}
                // 把最终的增强代理类放进BeanClass
				beanDef.setBeanClass(enhancedClass);
			}
		}
	}

代理执行

testBean01 实例化

createBeanInstance

doCreateBean 之后实例化对象时是

  • beanName = “testBean01” 的代理对象去执行

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

   		 // ******注意:@Bean方法的注册的bean FactoryMethodName 是有值得
         // 并且直接return
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod
实例化构造方法解析器
image.png
org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod
解析出 factoryBean
image.png
组装要实例化bean方法的参数
image.png
org.springframework.beans.factory.support.ConstructorResolver#instantiate

这里的 getInstantiationStrategy()指的是
InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
获取cgcib的一个策略执行器

image.png
反射执行

public class SimpleInstantiationStrategy implements InstantiationStrategy {

    private static final ThreadLocal<Method> currentlyInvokedFactoryMethod = new ThreadLocal<>();

    @Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
                              @Nullable Object factoryBean, final Method factoryMethod, Object... args) {

        try {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    ReflectionUtils.makeAccessible(factoryMethod);
                    return null;
                });
            }
            else {
                ReflectionUtils.makeAccessible(factoryMethod);
            }

            Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
            try {
                // 把当前正在执行的工厂方法扔进 ThreadLocal中,
                // 为什么这里要放入ThreadLocal中呢,等会参考 【testBean02 实例化】说明
                currentlyInvokedFactoryMethod.set(factoryMethod);

                /*
                factoryMethod是 要执行的方法:
              		  com.aaa.javabase.processor.BeanConfig#testBean01
				factoryBean是待执行方法的类:
    				  com.aaa.javabase.processor.BeanConfig(已经被gcblib代理过)
                */
                Object result = factoryMethod.invoke(factoryBean, args);
                if (result == null) {
                    result = new NullBean();
                }
                return result;
            }
            finally {
                if (priorInvokedFactoryMethod != null) {
                    currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
                }
                else {
                    currentlyInvokedFactoryMethod.remove();
                }
            }
        }
        catch (IllegalArgumentException ex) {
            throw new BeanInstantiationException(factoryMethod,
                                                 "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
                                                 "args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(factoryMethod,
                                                 "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
        }
        catch (InvocationTargetException ex) {
            String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
            if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
                ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
                msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
                "declaring the factory method as static for independence from its containing instance. " + msg;
            }
            throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
        }
    }

Spring#Cglib#拦截执行

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
image.png
image.png

testBean02 实例化

image.png
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor

private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {

    ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
    String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

    // Determine whether this bean is a scoped-proxy
    if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
    String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
    if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
        beanName = scopedBeanName;
    }


    // To handle the case of an inter-bean method reference, we must explicitly check the
    // container for already cached instances.

    // First, check to see if the requested bean is a FactoryBean. If so, create a subclass
    // proxy that intercepts calls to getObject() and returns any cached bean instance.
    // This ensures that the semantics of calling a FactoryBean from within @Bean methods
    // is the same as that of referring to a FactoryBean within XML. See SPR-6602.
    if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
        factoryContainsBean(beanFactory, beanName)) {
        Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
        if (factoryBean instanceof ScopedProxyFactoryBean) {
            // Scoped proxy factory beans are a special case and should not be further proxied
        }
        else {
            // It is a candidate FactoryBean - go ahead with enhancement
            return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
        }
    }

    /**
    当前线程正在执行的方法是 testbean02() 
    此方法内部包含 testBean01() 调用,
    此时当前线程正好执行testBean01(), 所以此时正在执行方法是testBean01()
    */
    if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
        // The factory is calling the bean method in order to instantiate and register the bean
        // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
        // create the bean instance.
        if (logger.isInfoEnabled() &&
            BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
            logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
                                      "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                                      "result in a failure to process annotations such as @Autowired, " +
                                      "@Resource and @PostConstruct within the method's declaring " +
                                      "@Configuration class. Add the 'static' modifier to this method to avoid " +
                                      "these container lifecycle issues; see @Bean javadoc for complete details.",
                                      beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
        }
        return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    }

    return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
				ConfigurableBeanFactory beanFactory, String beanName) {

			// 这里看一下此时的beanName是否是 getSingleton 阶段的bean
  			// 这里执行的是testBean02里面的调用的testBean01,显然不是
			boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
			try {
				if (alreadyInCreation) {
					beanFactory.setCurrentlyInCreation(beanName, false);
				}

                // 解析出@bean方法的构造参数
				boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
				if (useArgs && beanFactory.isSingleton(beanName)) {
					// Stubbed null arguments just for reference purposes,
					// expecting them to be autowired for regular singleton references?
					// A safe assumption since @Bean singleton arguments cannot be optional...
					for (Object arg : beanMethodArgs) {
						if (arg == null) {
							useArgs = false;
							break;
						}
					}
				}

                // 这里经过测试,无论@bean方法是否有入参,都可以根据beanName 查到 beanInstance
                // 这里返回的是testBean01的实例
				Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
						beanFactory.getBean(beanName));
				if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
					// Detect package-protected NullBean instance through equals(null) check
					if (beanInstance.equals(null)) {
						if (logger.isDebugEnabled()) {
							logger.debug(String.format("@Bean method %s.%s called as bean reference " +
									"for type [%s] returned null bean; resolving to null value.",
									beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
									beanMethod.getReturnType().getName()));
						}
						beanInstance = null;
					}
					else {
						String msg = String.format("@Bean method %s.%s called as bean reference " +
								"for type [%s] but overridden by non-compatible bean instance of type [%s].",
								beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
								beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
						try {
							BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
							msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
						}
						catch (NoSuchBeanDefinitionException ex) {
							// Ignore - simply no detailed message then.
						}
						throw new IllegalStateException(msg);
					}
				}

                // 从Threadlocal中拿到当前正在执行的顶级堆栈方法也就是 testBean02
				Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
				if (currentlyInvoked != null) {
                    // 从方法中解析出当前beanName=testBean02
					String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
					// 写入当前bean的依赖关系
                    // beanName =testBean01,outerBeanName =testBean02:
                    beanFactory.registerDependentBean(beanName, outerBeanName);
				}
                // 返回testbean01
				return beanInstance;
			}
			finally {
				if (alreadyInCreation) {
					beanFactory.setCurrentlyInCreation(beanName, true);
				}
			}
		}

}

当前调用的工厂方法是testbean02,而当前执行的方法是 testbean01,
做了一层判断:如果当前执行带@Bean方法方法不是当前调用的带@Bean方法,那么不再执行。
SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
这里取得是Threadlocal里面的内容对齐前面【testBean01 实例化】的过程中set的当前执行的带@Bean方法
image.png

结论

  1. 表明当前类是一个配置类,是方法bean的源
  2. 将@Configuration配置的AppConfig的beanDefinitioin属性赋值为full类型的,保证AppConfig类型 可以转变为cglib类型
  3. 将@Configuration配置的AppConfig由普通类型转变为cglib代理类型,后会生成cglib代理对象,通 过代理对象的方法拦截器,
    可以解决AppConfig内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值