上篇博客 主要说到了Spring IOC对bean类xml配置文件、使用反射等将其加载、解析并注册至Spring 容器中,以达到后期的使用操作。
但是,这个对象需要使用,依旧需要实例化操作,针对实例化,Spring就给整个项目进行了实现,但他是如何实现的?下面对此问题做具体分析。
依旧使用之前的测试代码。
@Test
public void spring() {
//1、获取beanfactory对象
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//2、获取xml文件解析器
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//3、加载指定xml文件,并自动解析、注册配置文件中的bean至beanFactory中
xmlBeanDefinitionReader.loadBeanDefinitions("bean1.xml");
UserDao ud = beanFactory.getBean(UserDao.class);
Assert.notNull(ud,"UserDao 不能为空");
ud.test();
}
以及调用的类
public class UserDao {
public void test() {
System.out.println("UserDao test .....");
}
public UserDao() {
System.out.println("UserDao().......");
}
}
由于Spring创建一个bean(对类的实例化操作),必将会调用这个类的构造方法
。由此本次测试断点
可以打在如下所示位置:
对spring()
使用debug
调试。
由debug运行代码方法栈,可以看出,通过Spring创建并获取到实例化对象时,会有三类流程:通过beanFactory获取到bean的相关信息(class)
、创建bean
、实例化bean
。
接下来对该三类流程做具体分析。
此时getBean(Class
中的requiredType
值为:
是一个类信息,标识了全路径名称等。
其中,经过了resolveNamedBean(requiredType, args)
操作,这个操作做了什么?
@Override
public String[] getBeanNamesForType(Class<?> type) {
return getBeanNamesForType(type, true, true);
}
@Override
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
//根据includeNonSingletons参数判断是否需要从缓存中获取
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
//在缓存集合中,依据 class cn.linkpower.di.UserDao 获取对应的bean的别名信息
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
经过处理后,此时的resolveNamedBean
操作中,根据getBeanNamesForType(requiredType)
获取到的数据信息为:[userDao]
。
之后会走下列流程。
即进入创建Bean环节。
其次,在doGetBean
操作中,会判断需要创建Bean的单例、多例类型性质
对象创建完成后,会校验对象是单例还是多例,如果是单例则找缓存,多例直接创建。
对象创建完成后,会继续判断对象中的依赖关系,进而对依赖的类实现创建操作。
创建Bean后,此时的bean
其中此时的instantiate
各项参数数据信息为:
RootBeanDefinition bd:
Root bean: class [cn.linkpower.di.UserDao]; scope=singleton; abstract=false;
lazyInit=false;autowireMode=0; dependencyCheck=0; autowireCandidate=true;
primary=false; factoryBeanName=null; factoryMethodName=null;
initMethodName=null; destroyMethodName=null;
defined in class path resource [bean1.xml]
String beanName :
BeanFactory owner :
org.springframework.beans.factory.support.DefaultListableBeanFactory@568ff82:
defining beans [testDemo1,userDao,userDaos]; root of factory hierarchy
org.springframework.beans.factory.support.instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner)
源码为:
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 判断 org.springframework.beans.factory.support.MethodOverrides中的Set 是否为空
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
//加锁
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
// 返回 包装好的Bean的类(假设已经解决了)。
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(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
//返回包装好的类的构造方法
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 调用该方法,传入 指定类的构造方法
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
调用 org.springframework.beans.instantiateClass(Constructor
对获取到的指定类的构造方法
使用反射
实例化出对象信息。