spring bean源码简单解析
来源:互联网 发布:iphone数据恢复软件 编辑:程序博客网 时间:2024/04/30 10:26
最近在看spring的源码,发现看这个还是有点早,看的很吃力,有多东西还不是很明白,像代理等,
我感觉spring用abstract模板来写主要功能,用接口来拓展功能,用的出神入化,但也让很多简单
的东西变得不那么好懂了,就是写的啰嗦了,个人感觉。下面就是下spring bean源码的学习:
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();new XmlBeanDefinitionReader(factory).loadBeanDefinitions(RETURNS_NULL_CONTEXT);Object result = factory.getBean("factoryBean");
这个就是整个spring bean的源码所做的整个解析,只是总体上的,基本上是三步:
1:加载xml,封装成Resource对象。
2:解析xml文件,相关的属性放到BeanDefinition,并把BeanDefinition放到BeanFactory中,实际就是beanDefinitionMap中。
3:通过getBean("factoryBean")方法来把对象注入。
下面来个直观点的东西:
从这个目录结构不难看出整个项目的具体思想,不具体说每个类和接口的作用了,下面具体说下载入解析xml的整个流程:
/** * Load bean definitions from the specified XML file. * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); }}第二段代码太长,不直观,只贴了关键一部分,从上面不难看出,具体做了3部分:
1:封装Resource资源,
2:获取输入流
3:调用doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法,也就是解析
/** * Actually load bean definitions from the specified XML file. * @param inputSource the SAX InputSource to read from * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException { try {int validationMode = getValidationModeForResource(resource);Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());return registerBeanDefinitions(doc, resource); }}这段代码也只截取了部分关键代码,具体说了三个意思:
1:获取xml验证模模式
2:获取Document对象
3:进行注册
这里的注册主要就是把拥有所有所有属性BeanDefinition放到map中,这里也可能是大多数不太明白的地方,笔者个人认为。
/** * Register the bean definitions contained in the given DOM document. * Called by {@code loadBeanDefinitions}. * <p>Creates a new instance of the parser class and invokes * {@code registerBeanDefinitions} on it. * @param doc the DOM document * @param resource the resource descriptor (for context information) * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of parsing errors * @see #loadBeanDefinitions * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader#registerBeanDefinitions */ public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
这里主要是说用BeanDefinitionDocumentReader来注册,解析工作。
/** * This implementation parses bean definitions according to the "spring-beans" XSD * (or DTD, historically). * <p>Opens a DOM Document; then initializes the default settings * specified at the {@code <beans/>} level; then parses the contained bean definitions. */public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;logger.debug("Loading bean definitions");Element root = doc.getDocumentElement();doRegisterBeanDefinitions(root);}
/** * Register each bean definition within the given root {@code <beans/>} element. */protected void doRegisterBeanDefinitions(Element root) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);if (!getEnvironment().acceptsProfiles(specifiedProfiles)) {return;}}// Any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(this.readerContext, root, parent);preProcessXml(root);parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;}
/** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate);}else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}
这三段代码比较简单,最后一段代码就是逐次遍历所有元素,像<bean/>等。下面重头戏来了,下面就是对得到的
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)) {// recursedoRegisterBeanDefinitions(ele);}}
/** * Process the given bean element, parsing the bean definition * and registering it with the registry. */protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.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));}}
/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {String id = ele.getAttribute(ID_ATTRIBUTE);String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);List<String> aliases = new ArrayList<String>();if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);aliases.addAll(Arrays.asList(nameArr));}String beanName = id;if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {beanName = aliases.remove(0);if (logger.isDebugEnabled()) {logger.debug("No XML 'id' specified - using '" + beanName +"' as bean name and " + aliases + " as aliases");}}if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);}AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {try {if (containingBean != null) {beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);}else {beanName = this.readerContext.generateBeanName(beanDefinition);// Register an alias for the plain bean class name, if still possible,// if the generator returned the class name plus a suffix.// This is expected for Spring 1.2/2.0 backwards compatibility.String beanClassName = beanDefinition.getBeanClassName();if (beanClassName != null &&beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {aliases.add(beanClassName);}}if (logger.isDebugEnabled()) {logger.debug("Neither XML 'id' nor 'name' specified - " +"using generated bean name [" + beanName + "]");}}catch (Exception ex) {error(ex.getMessage(), ele);return null;}}String[] aliasesArray = StringUtils.toStringArray(aliases);return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);}return null;}
/** * Parse the bean definition itself, without regard to name or aliases. May return * {@code null} if problems occurred during the parsing of the bean definition. */public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));String className = null;if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}try {String parent = null;if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);}AbstractBeanDefinition bd = createBeanDefinition(className, parent);parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));parseMetaElements(ele, bd);parseLookupOverrideSubElements(ele, bd.getMethodOverrides());parseReplacedMethodSubElements(ele, bd.getMethodOverrides());parseConstructorArgElements(ele, bd);parsePropertyElements(ele, bd);parseQualifierElements(ele, bd);bd.setResource(this.readerContext.getResource());bd.setSource(extractSource(ele));return bd;}catch (ClassNotFoundException ex) {error("Bean class [" + className + "] not found", ele, ex);}catch (NoClassDefFoundError err) {error("Class that bean class [" + className + "] depends on not found", ele, err);}catch (Throwable ex) {error("Unexpected failure during bean definition parsing", ele, ex);}finally {this.parseState.pop();}return null;}
这里主要对id,name,class,等属性的解读。也就是所说的属性注入到BeanDefinition,最后放到map中。
这只是整个流程,我没有详细解读,我感觉自己打上断点多走几遍更实际点。这些东西只是我个人的理解,
有不对的地方希望指出来,在此谢谢了。
对于对象的注入主要是AbstractAutowireCapableBeanFactory这个类来操作。这篇就不多说了,下篇再和大家探讨。
0 0
- spring bean源码简单解析
- Spring IOC 源码-bean解析
- Spring IOC 源码-bean解析
- Spring Bean加载源码解析
- Spring bean定义解析源码分析
- Spring IOC 源码-ClassPathXmlApplicationContext-bean解析
- Spring源码解析之Bean的加载
- Spring源码解析-bean的加载
- spring中扫描bean的源码解析
- Spring IOC 源码分析-bean标签解析
- spring 源码研究---bean包-- xml解析成bean对象
- 三 spring源码解析--- Bean解析接口结构分析
- spring源码阅读(七)之bean解析
- 【spring源码分析】--Bean的解析与注册
- Spring源码深度解析(五)加载Bean
- Spring源码阅读(2)- bean解析初体验
- spring源码深度解析(笔记四)--bean的加载
- Spring源码学习--Bean注入解析结果BeanDefinition
- How those spring enable annotations work
- Mybatis resultMap支持继承
- 【Ubuntu】Ubuntu 硬盘“分区”图文教程(用于光盘,U盘安装Ubuntu)
- Json学习笔记
- Animation 动画
- spring bean源码简单解析
- java编程思想并发学习笔记(rocket and rockets)
- leetcode_147_Insertion Sort Lis
- 模仿淘宝京东数量选择器
- 设计模式学习笔记七:策略模式
- Vaadin系列(二) 应用开发:Table 组件
- Openstack Keystone 认证流程(五)--路由
- Team Queue UVA 540 queue+map LRJ做法
- 详谈排序算法之插入类排序(两种思路实现希尔排序)