XmlBeanFactory

XmlBeanFactory

/** * A BeanDefinition describes a bean instance, which has property values, * constructor argument values, and further information supplied by * concrete implementations. * *<p>This is just a minimal interface: The main intention is to allow a * {@linkBeanFactoryPostProcessor} to introspect and modify property values * and other bean metadata. * *@authorJuergen Hoeller *@authorRob Harrop *@since19.03.2004 *@seeConfigurableListableBeanFactory#getBeanDefinition *@seeorg.springframework.beans.factory.support.RootBeanDefinition *@seeorg.springframework.beans.factory.support.ChildBeanDefinition */ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

案例

新增spring xml配置文件 ,xml配置注入对象student
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- xml配置注入对象--> <bean id="student" class="org.example.Student"/> </beans>
@SuppressWarnings("all") public class BeanFactoryDemo { public static void main(String[] args) { XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); Student student = (Student) beanFactory.getBean("student"); System.out.println(student.getName()); } }
notion image

Resource资源加载

notion image
不同的Resource实现类都实现类Resource接口 ,Resource接口中定义了资源状态判断的方法exists() , isFile(), isOpen()方法 ,提供了物理资源到File.URI以及URL等java概念的资源对象的转化方法,getFile方法可以将资源转化为File,getURI方法可以将资源转化为URI,get URL方法可以将资源转化为URL
notion image
public interface InputStreamSource { /** * Return an {@link InputStream} for the content of an underlying resource. * <p>It is expected that each call creates a <i>fresh</i> stream. * <p>This requirement is particularly important when you consider an API such * as JavaMail, which needs to be able to read the stream multiple times when * creating mail attachments. For such a use case, it is <i>required</i> * that each {@code getInputStream()} call returns a fresh stream. * @return the input stream for the underlying resource (must not be {@code null}) * @throws java.io.FileNotFoundException if the underlying resource doesn't exist * @throws IOException if the content stream could not be opened 返回底层资源内容的 InputStream。预计每次调用都会创建一个新的流。当您考虑像 JavaMail 这样的 API 时, 这个要求尤其重要,它需要能够在创建邮件附件时多次读取流。对于这样的用例,要求每个 getInputStream() 调用都返回一个新流 */ InputStream getInputStream() throws IOException; }
ClassPathResource 用来加载classpath路径下的资源文件
UrlResource, 加载URL
FileSystemResource 文件
ByteArrayResource Byte数组
InputStreamResource 实现类

XmlBeanFactory构造

最终会调用父类的构造函数
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) { this(); setParentBeanFactory(parentBeanFactory); } public AbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); }
通过注释了解到.这个方法是在自动注入过程中忽略给定的依赖接口
/** * Ignore the given dependency interface for autowiring. * <p>This will typically be used by application contexts to register * dependencies that are resolved in other ways, like BeanFactory through * BeanFactoryAware or ApplicationContext through ApplicationContextAware. * <p>By default, only the BeanFactoryAware interface is ignored. * For further types to ignore, invoke this method for each type. * @see org.springframework.beans.factory.BeanFactoryAware * @see org.springframework.context.ApplicationContextAware */ public void ignoreDependencyInterface(Class<?> ifc) { this.ignoredDependencyInterfaces.add(ifc); }
 

BeanNameAware

public class BeanFactoryDemo { public static void main(String[] args) { XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); BeanNameAwareImpl beanNameAwareImpl = (BeanNameAwareImpl) beanFactory.getBean("beanNameAwareImpl"); System.out.println(beanNameAwareImpl.getBeanName()); } }
notion image
ignoredDependencyInterfaces在检查依赖是否排除的方法里使用到
这个方法是用来决定指定的bean的属性是否从依赖检查里排除掉
/** * Determine whether the given bean property is excluded from dependency checks. * <p>This implementation excludes properties defined by CGLIB and * properties whose type matches an ignored dependency type or which * are defined by an ignored dependency interface. * @param pd the PropertyDescriptor of the bean property * @return whether the bean property is excluded * @see #ignoreDependencyType(Class) * @see #ignoreDependencyInterface(Class) */ protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) { return (AutowireUtils.isExcludedFromDependencyCheck(pd) || this.ignoredDependencyTypes.contains(pd.getPropertyType()) || AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces)); }
如果这个bean的属性指定了setter方法,返回true, 则这个属性值不会在自动注入的时候赋值
/** * Return whether the setter method of the given bean property is defined * in any of the given interfaces. * @param pd the PropertyDescriptor of the bean property * @param interfaces the Set of interfaces (Class objects) * @return whether the setter method is defined by an interface */ public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class<?>> interfaces) { Method setter = pd.getWriteMethod(); if (setter != null) { Class<?> targetClass = setter.getDeclaringClass(); for (Class<?> ifc : interfaces) { if (ifc.isAssignableFrom(targetClass) && ClassUtils.hasMethod(ifc, setter)) { return true; } } } return false; }
案例
public class BeanNameAwareImpl implements BeanNameAware { private String beanName; public String getBeanName(){ return beanName; } @Override public void setBeanName(String name) { this.beanName = name; } }
通过xml的方式注入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- xml配置注入对象--> <!-- <bean id="student" class="org.example.Student"/>--> <bean id="beanNameAwareImpl" class="org.example.BeanNameAwareImpl"> <property name="beanName" value="beanName"/> </bean> </beans>
测试获取bean名称
@SuppressWarnings("all") public class BeanFactoryDemo { public static void main(String[] args) { XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); BeanNameAwareImpl beanNameAwareImpl = (BeanNameAwareImpl) beanFactory.getBean("beanNameAwareImpl"); System.out.println(beanNameAwareImpl.getBeanName()); } }
notion image
通过bean注入的方式给字段beanName辅助没有生效, 最终获取到的是beanNameAwareImpl

loadBeanDefinitions

loadBeanDefinitions

文件校验

加载Document文件的时候调用 getValidationModeForResource 获取检验类型
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }
默认validationModeToUse = VALIDATION_AUTO
protected int getValidationModeForResource(Resource resource) { int validationModeToUse = getValidationMode(); if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } int detectedMode = detectValidationMode(resource); if (detectedMode != VALIDATION_AUTO) { return detectedMode; } // Hmm, we didn't get a clear indication... Let's assume XSD, // since apparently no DTD declaration has been found up until // detection stopped (before finding the document's root tag). return VALIDATION_XSD; }
notion image

将xml文件定义的bean注册到spring容器中

notion image
notion image
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); }
notion image
 
notion image
判断是否默认名称空间
notion image
bean标签对应的命名空间uri如下所示http://www.springframework.org/schema/beans
notion image
 
notion image

parseDefaultElement

DefaultBeanDefinitionDocumentReader 类的parseDefaultElement
public static final String NESTED_BEANS_ELEMENT = "beans"; public static final String ALIAS_ELEMENT = "alias"; public static final String NAME_ATTRIBUTE = "name"; public static final String ALIAS_ATTRIBUTE = "alias"; public static final String IMPORT_ELEMENT = "import"; public static final String RESOURCE_ATTRIBUTE = "resource"; public static final String PROFILE_ATTRIBUTE = "profile"; private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
查看解析bean标签的方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //1. 解析bean标签元素 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //2. 将解析到bean注册到spring容器中 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
 
@Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); }
最终调用了BeanDefinitionParserDelegateparseBeanDefinitionElement 方法
 
notion image
最终调用BeanDefinitionReaderUtilscreateBeanDefinition 方法
notion image
最终 new GenericBeanDefinition() 创建
notion image

BeanDefinition的属性设置

BeanDefinition的属性设置

BeanDefinition注册到spring容器

BeanDefinition注册到spring容器