vlambda博客
学习文章列表

二、spring源码初体验(XmlBeanFactory)

核心类

1.DefaultListableBeanFactory

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


BeanDefinitionReader:主要定义资源文件读取并转化为beanDefinitonEnvironmentCapable:定义获取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进行解析。

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

    以上代码的时序图(只截取与spring相关的关键部分)




尝试脚撕调用顺序

    先是构建ClassPathResource

// 先调用这个方法然后调用下面的重载方法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()

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

// 调用下面的重载方法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的父类DefaultListableBeanFactorypublic DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) { super(parentBeanFactory);}// 来到父类AbstractAutowireCapableBeanFactorypublic 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方法

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方法

// 返回加载的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); }}