核心类
1.DefaultListableBeanFactory
代码语言:javascript复制AliasRegistry:定义对alias的简单增删改等操作
SimpleAliasRegistry:主要使用map作为alias的缓存,并对接口AliasRegistry进行实现
SingletonBeanRegistry:定义对单例的注册及获取
BeanFactory:定义获取bean及bean的各种属性
DefaultSingletonBeanRegistry:对接口SingletonBeanRegistry各函数的实现
HierarchicalBeanFactory:继承BeanFactory,也就是在BeanFactory定义的功能的基础上增加了对parentFactory的支持
BeanDefinitionRegistry:定义对BeanDefinition的各种增删改操作
FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry基础上增加了对FactoryBean的特殊处理功能
ConfigurableBeanFactory:提供配置Factory的各种方法
ListableBeanFactory:根据各种条件获取bean的配置清单
AbstractBeanFactory:综合FactoryBeanRegistrySupport和ConfigurationBeanFactory的功能
AutowireCapableBeanFactory:提供创建bean、自动注入、初始化以及应用bean的后处理器
AbstractAutowireCapableBeanFactory:综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行实现
ConfigurableListableBeanFactory:BeanFactory配置清单,指定忽略类型及接口等
DefaultListableBeanFactory:综合上面所有功能,主要是对Bean注册后的处理
XmlBeanFactory对DefaultListableBeanFactory进行了扩展,主要用于从xml文档中读取BeanDefinition。对于注册及获取Bean都是使用从父类DefaultListableBeanFactory继承的方法去实现,而维度与父类不同的个性化实现就是增加了XmlBeanDefinitionReader类型的reader属性。在XmlBeanFactory中主要使用reader属性对资源文件进行读取和注册。
2.XmlBeanDefinitionReader
代码语言:javascript复制BeanDefinitionReader:主要定义资源文件读取并转化为beanDefiniton
EnvironmentCapable:定义获取Environment方法
DocumentLoader:定义从资源文件加载到转化为Document的功能。AbstractBeanDefinitionReader:对EnvironmntCapale、BeanDefinitionReader类定义的功能进行实现。BeanDefinitionDocumentReader:定义读取Document并注册Beandefinition功能
BeanDefinitionParserDelegate:定义解析Element的各种方法。
1.继承自AbstractBeanDefinitionReader中的方法,来使用ResourceLoaner将资源文件转换成对应的Resource文件。
2.通过DocumentLoader对Resource文件进行转换,将Resource文件转换成Document文件。
3.通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析。
代码语言:javascript复制BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
以上代码的时序图(只截取与spring相关的关键部分)
尝试脚撕调用顺序
先是构建ClassPathResource
代码语言:javascript复制// 先调用这个方法然后调用下面的重载方法
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
// 上面的方法调用的这个
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path); // 将字符串中的"\"转换成"/"
if (pathToUse.startsWith("/")) { // 兼容逻辑地址
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
点击进入ClassUtils.getDefaultClassLoader()
代码语言:javascript复制public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
// 获取当前的线程类的类加载器,这是目前最安全的办法,防止部署到tomcat里时候其他资源是用tomcat内部加载,而这里用的是jdk的类加载器)
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back... // 只是不让异常抛出,不做处理
}
if (cl == null) { // 如果无法获取到
// No thread context class loader -> use class loader of this class.
// 注释写的很清楚,如果拿不到线程上下文的类加载器,就用当前类(spring的classUtils)的类加载器
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader(); // 会初始化系统类加载器,并且类加载器是classloader的类加载器,则返回这个加载器
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
// 大佬还是很幽默的,如果连系统类的类加载器都没有。那么,可能这些东西都能跑在null上?}
}
}
return cl;
}
于是乎ClassPathResource就有了两个必须属性,classPath和classLoader
然后回到构建XmlBeanFactory
代码语言:javascript复制// 调用下面的重载方法
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
// 先解读第一句代码super,来到XmlBeanFactory的父类DefaultListableBeanFactory
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
// 来到父类AbstractAutowireCapableBeanFactory
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory); // 普通的set,后面再解释用来干嘛的这个factory
}
// this()就是调用空构造方法
public AbstractAutowireCapableBeanFactory() {
super(); // 调用AbstractBeanFactory的空构造方法(里面什么都没有,就不跟进了)
// 将这个类放进 private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
// 意思是在自动装配时忽略指定接口的实现类中字段依赖的注入
// 这样的做法使得BeanFactoryAware的实现类中的BeanFactory依赖在自动装配时被忽略,而统一由框架设置依赖
// 如ApplicationContextAware接口的设置会在ApplicationContextAwareProcessor类中完成ApplicationContext的注入
// 保证了ApplicationContextAware和BeanFactoryAware中的容器保证是生成该bean的容器
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class); // 还有一个类似的ignoreDependencyType 是注入时忽略这个类型的参数注入
}
然后我们回到XmlBeanFactory的构造方法中的this.reader.loadBeanDefinitions方法
代码语言:javascript复制public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
// 先进入EncodedResource的构造方法
public EncodedResource(Resource resource) {
this(resource, null, null);
}
// 调用重载的方法,其实就是设置值,然后返回一个EncodedResource对象
private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
super(); // object类的构造函数,之前在Object的源码分析的时候看过了
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.encoding = encoding;
this.charset = charset;
}
// 返回XmlBeanDefinitionReader类的loadBeanDefinitions方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " encodedResource);
}
// 获取ThreadLocal中的数据Set,ThreadLocal的get方法如果没有数据就返回null
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
// 如果ThreadLocal中没有数据,则new一个HashSet,并且放到这个对象的属性中
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
// 如果放入set失败,则报错(后面加载完要删除的)
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " encodedResource " - check your import definitions!");
}
try {
// 配置文件的inputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
// 资源加载失败
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " encodedResource.getResource(), ex);
}
finally {
// 删除刚刚加载的资源
currentResources.remove(encodedResource);
// 如果ThreadLocalMap已经是空的,就从ThreadLocal中删除
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
然后进入43行的doLoadBeanDefinitions方法
代码语言:javascript复制// 返回加载的bean数量
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 通过inputSource 转换成Document对象(中间有用过factory模式和Builder模式)
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " ex.getLineNumber() " in XML document from " resource " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " resource " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " resource, ex);
}
}