文档章节

Spring源码阅读-实例化策略InstantiationStrategy

Small-Liu
 Small-Liu
发布于 2017/01/12 14:23
字数 1012
阅读 345
收藏 0

策略流程

spring中角色分工很明确,创建对象的时候先通过 ConstructorResolver找到对应的实例化方法和参数,再通过实例化策略InstantiationStrategy进行实例化,根据创建对象的三个分支( 工厂方法、有参构造方法、无参构造方法 ), InstantiationStrategy提供了三个接口方法:

public interface InstantiationStrategy {

	//默认构造方法
	Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) throws BeansException;

	//指定构造方法
	Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner, Constructor<?> ctor,
			Object[] args) throws BeansException;

	//指定工厂方法
	Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner, Object factoryBean,
			Method factoryMethod, Object[] args) throws BeansException;

}

在SimpleInstantiationStrategy中对这三个方法做了简单实现,如果工厂方法实例化直接用反射创建对象,如果是构造方法实例化的则判断是否有MethodOverrides,如果有无MethodOverrides也是直接用反射,如果有MethodOverrides就需要用cglib实例化对象,SimpleInstantiationStrategy把通过cglib实例化的任务交给了它的子类CglibSubclassingInstantiationStrategy。

MethodOverrides

先看一下MethodOverrides对应的配置是在什么地方,找到解析标签元素的地方,

类BeanDefinitionParserDelegate在解析bean标签的时候 发现了下面两个方法:

方法parseLookupOverrideSubElements解析标签lookup-method,

方法parseReplacedMethodSubElements解析标签replaced-method

这两个标签是配置在bean标签的下一级,并且replaced-method还有自己的子标签

cglib策略

Cglib的实例化策略里是通过它的内部类CglibSubclassCreator来实例化:

protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition, String beanName,
		BeanFactory owner, Constructor<?> ctor, Object[] args) {

	// Must generate CGLIB subclass.
	return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args);
}

看CglibSubclassCreator:

private static class CglibSubclassCreator {

        //这里的数组位置很重要, 后面MethodOverrideCallbackFilter通过指定下标获取对应的拦截
	private static final Class<?>[] CALLBACK_TYPES = new Class<?>[] { NoOp.class,
			LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class };

	private final RootBeanDefinition beanDefinition;

	private final BeanFactory owner;

	CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
		this.beanDefinition = beanDefinition;
		this.owner = owner;
	}

	//实例化入口:动态构造子类
	Object instantiate(Constructor<?> ctor, Object[] args) {
		Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
		Object instance;
		if (ctor == null) {
			instance = BeanUtils.instantiate(subclass);
		} else {
			try {
				Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
				instance = enhancedSubclassConstructor.newInstance(args);
			} catch (Exception ex) {
				throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), String.format(
						"Failed to invoke constructor for CGLIB enhanced subclass [%s]", subclass.getName()), ex);
			}
		}
		//这个地方解决一个bug,bug提交报告https://jira.spring.io/browse/SPR-10785
		// SPR-10785: set callbacks directly on the instance instead of in the
		// enhanced class (via the Enhancer) in order to avoid memory leaks.
		Factory factory = (Factory) instance;
		factory.setCallbacks(new Callback[] { NoOp.INSTANCE,
				new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
				new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner) });
		return instance;
	}

	/**
	 * Create an enhanced subclass of the bean class for the provided bean
	 * definition, using CGLIB.
	 */
	private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
		//cglib里面的用法,对原始class进行增强,并设置callback
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(beanDefinition.getBeanClass());
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		//过滤,自定义逻辑来指定调用的callback下标(callback会以数组的方式传人)
		enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
		//只是生产class就直接指定callback类型,跟上面CallbackFilter对应
		enhancer.setCallbackTypes(CALLBACK_TYPES);
		return enhancer.createClass();
	}
}

以instantiate为入口通过cglib的Enhancer生成subClass, 这里生成subClass的时候传人了原始class和Callback,并通过MethodOverrideCallbackFilter里面定义调用callback类型:

private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {
	//...

	@Override
	public int accept(Method method) {
		//配置文件加载到MethodOverrides集合中
		MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
		if (logger.isTraceEnabled()) {
			logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
		}
		if (methodOverride == null) {
			return PASSTHROUGH;//0
		} else if (methodOverride instanceof LookupOverride) {
			return LOOKUP_OVERRIDE;//1
		} else if (methodOverride instanceof ReplaceOverride) {
			return METHOD_REPLACER;//2
		}
		throw new UnsupportedOperationException(
				"Unexpected MethodOverride subclass: " + methodOverride.getClass().getName());
	}
}

这里的PASSTHROUGH,LOOKUP_OVERRIDE,METHOD_REPLACER常量值和所有调用Callbak数组下标对应,分别是LOOKUP_OVERRIDE对应着LookupOverrideMethodInterceptor,METHOD_REPLACER对应着ReplaceOverrideMethodInterceptor,分别看这两种callback业务:

  • LookupOverrideMethodInterceptor:
    private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
    
    	private final BeanFactory owner;
    
    	LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
    		super(beanDefinition);
    		this.owner = owner;
    	}
    
    	@Override
    	public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
    		// Cast is safe, as CallbackFilter filters are used selectively.
    		LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
    		return this.owner.getBean(lo.getBeanName());
    	}
    }

    直接把lookup-method配置的对象返回,这个用于插拔式程序特别方便

  • ReplaceOverrideMethodInterceptor

    private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
    
    	private final BeanFactory owner;
    
    	ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
    		super(beanDefinition);
    		this.owner = owner;
    	}
    
    	@Override
    	public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
    		ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
    		// TODO could cache if a singleton for minor performance
    		// optimization
    		MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
    		return mr.reimplement(obj, method, args);
    	}
    }

    通过methodReplacerBeanName获取替换对象,该对象实现了MethodReplacer接口,获取到该对象后调用reimplement方法。

© 著作权归作者所有

共有 人打赏支持
Small-Liu
粉丝 17
博文 56
码字总数 49976
作品 0
南京
程序员
私信 提问
Spring Bean生命周期-阶段汇总,面试必备(十二)

以后面试问到Bean的生命周期再也不怕了! 看了这么久的Spring源码,想必对Spring的生命周期已经有了一定的了解,这次将之前零散的生命周期处理的事情贯穿起来,看过之后,一定对bean的生命周...

Real_man
10/18
0
0
说说 Spring 容器的技术内幕

Spring 的 AbstractApplicationContext 是 ApplicationContext 的抽象实现类,这个类的 refresh() 方法定义了 Spring 容器在加载配置文件之后的处理过程: 下面列出重要的方法名与说明: 重点...

deniro
05/17
0
0
Spring IOC 启动过程

引言 本篇博文主要介绍 IOC 容器的启动过程,启动过程分为两个步骤,第一个阶段是容器的启动阶段,第二个阶段是 Bean 实例化阶段,这两个阶段各自需要执行的步骤如下图,接下来会一一介绍。 ...

firepation
09/04
0
0
再谈Spring BeanPostProcessor

之前已经就spring中的BeanPostProcessor使用方法以及其实现细节谈论过,现在从更加宏观、抽象的角度去理解spring的bpp具体是如何工作的,现在spring自身有多少bpp,如果我们有自定义的bpp需求...

jwfy
07/03
0
0
Spring IOC 容器源码分析 - 创建原始 bean 对象

1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续。在上一篇文章中,我们从战略层面上领略了方法的全过程。本篇文章,我们就从战术的层面上,详细分析方法中的一个重要的调用,即...

coolblog.xyz
06/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring源码学习笔记-1-Resource

打算补下基础,学习下Spring源码,参考书籍是《Spring源码深度解析》,使用版本是Spring 3.2.x,本来想试图用脑图记录的,发现代码部分不好贴,还是作罢,这里只大略记录下想法,不写太细了 ...

zypy333
今天
10
0
RestClientUtil和ConfigRestClientUtil区别说明

RestClientUtil directly executes the DSL defined in the code. ConfigRestClientUtil gets the DSL defined in the configuration file by the DSL name and executes it. RestClientUtil......

bboss
今天
17
0

中国龙-扬科
昨天
2
0
Linux系统设置全局的默认网络代理

更改全局配置文件/etc/profile all_proxy="all_proxy=socks://rahowviahva.ml:80/"ftp_proxy="ftp_proxy=http://rahowviahva.ml:80/"http_proxy="http_proxy=http://rahowviahva.ml:80/"......

临江仙卜算子
昨天
10
0
java框架学习日志-6(bean作用域和自动装配)

本章补充bean的作用域和自动装配 bean作用域 之前提到可以用scope来设置单例模式 <bean id="type" class="cn.dota2.tpye.Type" scope="singleton"></bean> 除此之外还有几种用法 singleton:......

白话
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部