二、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, 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 ClassLoadertry {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( BeanFactory parentBeanFactory) {super(parentBeanFactory);}// 来到父类AbstractAutowireCapableBeanFactorypublic AbstractAutowireCapableBeanFactory( 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方法如果没有数据就返回nullSet<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 {// 配置文件的inputStreamInputStream 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);}}
