2019.10.27笔记——@Configuration的底层实现

@Configuration的底层实现

@Configuration的底层实现

上面的文章中已经大致解析了@Configuration的实现,对于cglib代理之外的解析已经很完善了,不过并没有细致分析其中的cglib动态代理,现在在这里只会关注其中对于cglib动态代理的实现。

这里会先简单介绍以下cglib动态代理

cglib动态代理

假设有下面的需要代理的目标对象

public class Target {
	public void test(){
		System.out.println("test");
	}
}

代理的逻辑可以写在实现MethodInterceptor的对象中,具体在intercept方法中会有其中的代理逻辑

public class MyMethodInterceptor implements MethodInterceptor {
	/**
	 *
	 * @param o				目标实例对象
	 * @param method
	 * @param objects		方法的参数
	 * @param methodProxy	代理对象的方法,就是下面的方法,相当于方法自身
	 * @return
	 * @throws Throwable
	 */
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		// 代理逻辑
		System.out.println("代理逻辑");
		// 执行父类的方法,就是目标对象的原生方法,返回返回值
		return methodProxy.invokeSuper(o,objects);
	}
}

测试

public static void main(String[] args) {
	// 先创建一个代理对象
	Enhancer enhancer = new Enhancer();
	// 要代理的对象的class
	enhancer.setSuperclass(Target.class);
	// 设置代理的回调,也就是代理的逻辑,Callback的实现类
	enhancer.setCallback(new MyMethodInterceptor());
	// 获得最终的代理对象
	Target target = (Target) enhancer.create();
	target.test();
}

在这里插入图片描述

spring中的cglib动态代理

在bean工厂后置处理器的回调方法中enhanceConfigurationClasses是处理cglib动态代理的,而其中的enhance方法则是生成代理对象的。
在这里插入图片描述

org.springframework.context.annotation.ConfigurationClassEnhancer#enhance

public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {

	//判断是否被代理过
	if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
		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;
	}
	//通过newEnhancer返回一个cglib代理对象
	//在这个new的过程也是spring对需要代理的中的方法和属性的处理
	Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
	if (logger.isDebugEnabled()) {
		logger.debug(String.format("Successfully enhanced %s; enhanced class name is: %s",
				configClass.getName(), enhancedClass.getName()));
	}
	return enhancedClass;
}

newEnhancer方法中会真正创建其代理对象的Enhancer对象,需要关注其中的CALLBACK_FILTER,这个执行代理逻辑的对象是ConfigurationClassEnhancer的内部类BeanMethodInterceptor。

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
	//先创建一个代理对象
	Enhancer enhancer = new Enhancer();
	//要代理的对象的class
	enhancer.setSuperclass(configSuperClass);
	//设置一个接口
	//便于增强
	enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
	enhancer.setUseFactory(false);
	//设置名字的生成策略
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	//BeanFactoryAwareGeneratorStrategy是一个生成策略
	//主要为生成的cglib类中添加成员变量$$beanFactory
	enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
	//过滤方法,不能每次都去new
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	return enhancer;
}

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor

在这个对象的intercept方法就会处理

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
			MethodProxy cglibMethodProxy) throws Throwable {

	ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
	// 拿到此时生成bd的beanName
	String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

	// Determine whether this bean is a scoped-proxy
	Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class);
	if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
		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.
	// 下面直接通过getBean方法创建对象
	// 一般情况不会进入,特殊的bd
	if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
			factoryContainsBean(beanFactory, beanName)) {
		// 实例化bean,拿到bean对象
		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);
		}
	}

	// 判断当前方法实例化的bean是不是外部方法
	// 如果当前方法是@Bean注解方法中的方法,那么此时实例化的bean的名字自然不是当前方法对应的方法
	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.isWarnEnabled() &&
				BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
			logger.warn(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()));
		}
		// 如果没有其他bean的实例化方法直接调用原生方法
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}
	// 如果当前方法属于方法内部的方法,那么就通过下面的方法实例化(得到,可能已经实例化过了)bean
	return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

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

	// The user (i.e. not the factory) is requesting this bean through a call to
	// the bean method, direct or indirect. The bean may have already been marked
	// as 'in creation' in certain autowiring scenarios; if so, temporarily set
	// the in-creation status to false in order to avoid an exception.
	boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
	try {
		if (alreadyInCreation) {
			beanFactory.setCurrentlyInCreation(beanName, false);
		}
		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;
				}
			}
		}
		// 同样是通过getBean拿到bean对象
		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);
			}
		}
		Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
		if (currentlyInvoked != null) {
			String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
			beanFactory.registerDependentBean(beanName, outerBeanName);
		}
		return beanInstance;
	}
	finally {
		if (alreadyInCreation) {
			beanFactory.setCurrentlyInCreation(beanName, true);
		}
	}
}

上面的方法中大致的逻辑如下

  1. 判断是不是方法内部方法,不过如果是第一次调用那么一定是外部方法,那么会调用原生方法初始化bean对象。
  2. 在执行原生方法时可能会执行其他实例化bean的方法,此时就会再次进入intercept方法,并且再次判断是不是方法内部方法,此时一定是,那么会resolveBeanReference方法实例化对象,最终会通过getBean方法实例化对象。这里的getBean方法并不是单纯调用@Bean注解的实例化方法,可以说是直接从单例池map中拿到bean对象。这个方法的详细分析可以参考《bean初始化(实例化)详解》和《spring的循环依赖分析》中对getBean方法的解析。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值