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());
}
}