Spring源码IOC之无参实例化策略

2.6 无参实例化策略

上文提到了IOC实例化bean的几种策略,接下来的小节,重点分析无参、有参两种实例化策略。因为无参策略较为简单,所以先分析该策略。

入口代码:

// 获取实例化策略,并实例化bean
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
2.6.1 getInstantiationStrategy 获取实例化策略
/** Strategy for creating bean instances. 创建 bean 实例的策略。*/
private InstantiationStrategy instantiationStrategy;

/**
 * Set the instantiation strategy to use for creating bean instances.
 * Default is CglibSubclassingInstantiationStrategy.
 * 设置用于创建 bean 实例的实例化策略。 默认为 CglibSubclassingInstantiationStrategy。
 * @see CglibSubclassingInstantiationStrategy
 */
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
	this.instantiationStrategy = instantiationStrategy;
}

/**
 * Return the instantiation strategy to use for creating bean instances.
 * 返回用于创建 bean 实例的实例化策略
 */
protected InstantiationStrategy getInstantiationStrategy() {
	return this.instantiationStrategy;
}

从代码中可以看到,IOC通过InstantiationStrategy接口来管理实例化策略,并且默认为CglibSubclassingInstantiationStrategy。但是IOC容器并没有显示的调用setInstantiationStrategy设置实例化策略,而是通过AbstractAutowireCapableBeanFactory的构造方法来创建实例化策略。

public AbstractAutowireCapableBeanFactory() {
	super();
	ignoreDependencyInterface(BeanNameAware.class);
	ignoreDependencyInterface(BeanFactoryAware.class);
	ignoreDependencyInterface(BeanClassLoaderAware.class);
	if (NativeDetector.inNativeImage()) {
		this.instantiationStrategy = new SimpleInstantiationStrategy();
	}
	else {
	   // 实例化 CglibSubclassingInstantiationStrategy
		this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
	}
}
2.6.2 实例化策略概览

上一步拿到实例化策略后,就可以实例化bean了。

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
	// Don't override the class with CGLIB if no overrides.
	// 无方法注入,使用反射
	if (!bd.hasMethodOverrides()) {
		Constructor<?> constructorToUse;
		synchronized (bd.constructorArgumentLock) {
			constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
			// 若缓存的构造方法为空,则解析构造方法
			if (constructorToUse == null) {
				final Class<?> clazz = bd.getBeanClass();
				// 接口不能被实例化
				if (clazz.isInterface()) {
					throw new BeanInstantiationException(clazz, "Specified class is an interface");
				}
				try {
					if (System.getSecurityManager() != null) {
						constructorToUse = AccessController.doPrivileged(
								(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
					}
					else {
						// 获取构造方法
						constructorToUse = clazz.getDeclaredConstructor();
					}
					// 缓存构造方法
					bd.resolvedConstructorOrFactoryMethod = constructorToUse;
				}
				catch (Throwable ex) {
					throw new BeanInstantiationException(clazz, "No default constructor found", ex);
				}
			}
		}
		// 实例化
		return BeanUtils.instantiateClass(constructorToUse);
	}
	else {
		// Must generate CGLIB subclass.
		// 存在方法注入,必须使用 CGLIB
		return instantiateWithMethodInjection(bd, beanName, owner);
	}
}

无方法注入,使用反射;否则,必须使用CGLIB

2.6.3 反射
  • 获取构造方法
    • constructorToUse = clazz.getDeclaredConstructor(); 通过Class类的getDeclaredConstructor()方法获取构造函数。因为这里是无参策略,所以无需传递任何参数。获取到构造方法后,再将其缓存到resolvedConstructorOrFactoryMethod中,方便下次使用。
  • 通过BeanUtils创建对象实例
    • 通过Constructor类的newInstance方法创建对象实例
2.6.4 CGLIB

若存在方法注入(replace-method、lookup-method)则必须使用CGLIB。

public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
	// 创建增强子类
	Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
	Object instance;
	// 无参实例化
	if (ctor == null) {
		instance = BeanUtils.instantiateClass(subclass);
	}
	// 有参实例化
	else {
		try {
			// 获取有参构造函数
			Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes(
			// 实例化
			instance = enhancedSubclassConstructor.newInstance(args);
		}
		catch (Exception ex) {
			throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
					"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + 
		}
	}
	// SPR-10785: set callbacks directly on the instance instead of in the
	// enhanced class (via the Enhancer) in order to avoid memory leaks.
	// 为了避免内存泄漏,直接在实例上设置回调,而不是在增强类中(通过Enhancer)。
	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.
 * 使用 CGLIB 为提供的 bean 定义创建 bean 类的增强子类。
 */
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(beanDefinition.getBeanClass());
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	if (this.owner instanceof ConfigurableBeanFactory) {
		ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
		enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
	}
	enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
	enhancer.setCallbackTypes(CALLBACK_TYPES);
	return enhancer.createClass();
}

Spring使用了Enhancer来创建增强子类,因为是动态字节码,所以我们需要将生成的增强文件保存到磁盘。在测试方法中添加:

// 替换成自己的路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/liyanchao/Downloads");

OK,接下来就可以看到生成的增强子类了,因为代码较多,只粘贴核心代码:

public class OriginalDog$$EnhancerBySpringCGLIB$$236d11d6 extends OriginalDog implements Factory {
    public final void sayHello() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_2;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_2;
        }
        if (var10000 != null) {
            // 拦截方法
            var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
        } else {
            super.sayHello();
        }
    }
}

有了增强子类后,接下来通过instance = BeanUtils.instantiateClass(subclass);创建对象实例,注意:这里创建的实例已经不是我们原始Bean的实例了,而是增强子类的实例。

当调用增强类中的方法时,会被intercept()方法拦截:

// replace_method
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
	ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
	Assert.state(ro != null, "ReplaceOverride not found");
	// 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);
}
// lookup_method
@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);
	Assert.state(lo != null, "LookupOverride not found");
	Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
	if (StringUtils.hasText(lo.getBeanName())) {
		Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
				this.owner.getBean(lo.getBeanName()));
		// Detect package-protected NullBean instance through equals(null) check
		return (bean.equals(null) ? null : bean);
	}
	else {
		// Find target bean matching the (potentially generic) method return type
		ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
		return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
				this.owner.getBeanProvider(genericReturnType).getObject());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲来也无事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值