文档章节

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

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

精选30+云产品,助力企业轻松上云!>>>

策略流程

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
粉丝 20
博文 56
码字总数 49976
作品 0
南京
程序员
私信 提问
加载中
请先登录后再评论。
【趣味设计模式系列】之【策略模式】

1. 简介 策略模式(strategy):定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。 2. 图解 商城搞多种优惠活动,顾客只能参与其中一种优惠算法。 3. 案例实现 类图 满200减20元...

小猪爸爸
05/06
0
0
【趣味设计模式系列】之【策略模式】

简介 策略模式(strategy):定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。 2. 图解 商城搞多种优惠活动,顾客只能参与其中一种优惠算法。 3. 案例实现 类图 满200减20元;...

osc_zf8orajc
05/07
7
0
spring ApplicationContext中Bean的生命周期

AbstractApplicationContext Spring的AbstractApplicationContext是ApplicationContext的抽象实现类,该抽象类的refresh方法定义了spring容器在加载配置文件后的各项处理过程 public void re...

osc_mpdk2b71
2019/01/15
3
0
Spring Bean生命周期-阶段汇总,面试必备(十二)

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

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

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

deniro
2018/05/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Free RTOS学习随笔(1),临界区代码

Free RTOS学习随笔(1),临界区代码 基本介绍 Free RTOS中临界区代码常用函数 任务级临界代码保护 调用方式 实现原理 中断级临界代码保护 调用方式 实现原理 基本介绍 临界区代码指的是那些...

osc_ho8dcqsx
21分钟前
5
0
STM32单片机驱动步进电机—简单篇

STM32单片机驱动步进电机(一) 驱动电机运动 软件:Keil5 设备:步进电机(17HS4401)、驱动器、单片机(STM32F103) 接线方式: 电机与驱动器:黑A+,绿A-,红B+,蓝B- 驱动器与单片机:M...

osc_2qah5avr
22分钟前
18
0
龙芯开源社区上线.NET主页

龙芯团队从2019年7 月份开始着手.NET Core的MIPS64支持研发,经过将近一年的研发,在2020年6月18日完成了里程碑性的工作,在github CoreCLR 仓库:https://github.com/gsvm/coreclr, 随后受...

osc_923iryp1
24分钟前
9
0
计算机组成原理笔记(二)

我的博客: https://www.luozhiyun.com/ 浮点数和定点数 我们先来看一个问题,在Chrome浏览器里面通过开发者工具,打开浏览器里的Console,在里面输入“0.3 + 0.6”: >>> 0.3 + 0.60.8999...

osc_1psr53ow
24分钟前
19
0
Vue PDF文件预览vue-pdf

最近做项目,遇到预览PDF这个功能,在网上找了找,大多推荐的是pdf.js,不过在Vue中还是想偷懒直接npm组件,最后找到了一个还不错的Vue-pdf 组件,GitHub地址:https://github.com/FranckFreiburge...

osc_1i3ltp99
25分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部