摘要:本文是针对的来进行解析并将解析后的信息使用作为载体进行注册已经在中被标记为不建议使用,但是我们分析源码不影响,因为源码并未改变,并依旧使用和进行的解析和注册工作,本篇博客是跟源码一步步看怎么实现的注册,源码为源码已经在每一行上加了注释,方便
本文是针对Srping的XMLBeanFactory来进行解析xml并将解析后的信息使用GenericBeanDefinition作为载体进行注册,xmlBeanFactory已经在Spring 3.1中被标记为不建议使用,但是我们分析源码不影响,因为源码并未改变,并ApplicationContext依旧使用XmlBeanDefinitionReader和DefaultListableBeanFactory进行xml的解析和注册工作,本篇博客是跟源码一步步看spring怎么实现bean的注册,源码为spring5.X,源码已经在每一行上加了注释,方便读者学习。
GitHub: https://github.com/lantaoGitH...
首先我们从XMLBeanFactory入手,直接上代码:
package org.springframework.lantao; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class XmlBeanFactoryTest { public static void main(String[] args) { // 资源加载 ClassPathResource classPathResource = new ClassPathResource("spring-bean.xml"); // XmlBeanFactory 加载资源并解析注册bean BeanFactory beanFactory = new XmlBeanFactory(classPathResource); // BeanFactory.getBean(); UserBean userBean = (UserBean) beanFactory.getBean("userBean"); System.out.println(userBean.getName()); } }
XmlBeanFactory解析Xml是使用了XmlBeanDefinitionReader.loadBeanDefinition()方法,源码如下:
@Deprecated @SuppressWarnings({"serial", "all"}) public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); /** * Create a new XmlBeanFactory with the given resource, * which must be parsable using DOM. * @param resource the XML resource to load bean definitions from * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource) throws BeansException { //调用构造方法 79行 this(resource, null); } /** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * @param resource the XML resource to load bean definitions from * @param parentBeanFactory parent bean factory * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { //ignoreDependencyInterface 忽略自动装配 //主要功能就是当有忽略的接口类,自动装配会忽略这部分类的初始化装配,因为某种情况下,此时的接口实现类不能初始化,列如BeanNameAware,要想装配这个接口的实现对象,可以实现这个接口。 super(parentBeanFactory); //这段代码是真正的资源加载 this.reader.loadBeanDefinitions(resource); } }
我们直接看loadBeanDefinition方法,源码:
/** * 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 */ @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { // 对EncodedResource进行封装,设置String encoding, Charset charset return loadBeanDefinitions(new EncodedResource(resource)); } /** * Load bean definitions from the specified XML file. * @param encodedResource the resource descriptor for the XML file, * allowing to specify an encoding to use for parsing the file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { //encodedResource 不可以为空 Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } // 通过属性来记录已经加载的资源 SetcurrentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { // 从encodedResource已经封装的Resource获取InputStream InputStream inputStream = encodedResource.getResource().getInputStream(); try { //InputSource 并不是spring的,而是 org.xml.sax InputSource inputSource = new InputSource(inputStream); //如果encodedResource 中的 Encoding 不是 null 则同步设置 InputSource的 Encoding if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //加载bean的Definitions 将xml中的信息加载到Definition中,并且在内存中注册的也是key+definitions 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); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
上述源码可能看着比较长,但实际上这里并不是真正解析的地方,在这里做了如下:1:从encodedResource已经封装的Resource获取InputStream;
2:如果encodedResource 中的 Encoding 不是 null 则同步设置 InputSource的 Encoding;
3:将解析动作委托给doLoadBeanDefinitions实现;
接下来我们继续看doLoadBeanDefinitions方法内容:
/** * 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 * @see #doLoadDocument * @see #registerBeanDefinitions */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //加载 Document Document doc = doLoadDocument(inputSource, resource); //注册 bean int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } 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); } }
当我们看着这个方法的时候,依旧不是真正的解析或注册的方法,在这里只是做了Document的加载,并将后续工作委托给了registerBeanDefinitions,registerBeanDefinitions方法的返回时注册Bean的个数;
我们继续看registerBeanDefinitions的源码:
/** * Register the bean definitions contained in the given DOM document. * Called by {@code loadBeanDefinitions}. *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 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //获取之前的beanDefinition加载个数 int countBefore = getRegistry().getBeanDefinitionCount(); //加载xml及注册bean documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //记录本次加载个数 return getRegistry().getBeanDefinitionCount() - countBefore; }
在registerBeanDefinitions方法具体实现:1:通过BeanUtils.instantiateClass(this.documentReaderClass)的方法实例化BeanDefinitionDocumentReader;
2:通过DefaultListAbleBeanFactory中的beanDefinitionMap.size()获取之前注册bean的个数,(beanDefinitionMap是存储最终的xml解析后信息的载体,xml解析后信息是由GenericBeanDefinition进行存储,beanDefinitionMap的存储格式是key:String value:GenericBeanDefinition)
3:将解析xml和注册的工作委托给BeanDefinitionDocumentReader的registerBeanDefinitions方法;
4:记录本次加载个数并返回;
继续看BeanDefinitionDocumentReader的registerBeanDefinitions方法:
/** * This implementation parses bean definitions according to the "spring-beans" XSD * (or DTD, historically). *Opens a DOM Document; then initializes the default settings * specified at the {@code
} level; then parses the contained bean definitions. */ @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { //实例化 ReaderContext this.readerContext = readerContext; //注册 doRegisterBeanDefinitions(doc.getDocumentElement()); }
registerBeanDefinitions并没有做什么,我们继续看doRegisterBeanDefinitions方法:
/** * Register each bean definition within the given root {@code} element. */ @SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...) protected void doRegisterBeanDefinitions(Element root) { // Any nested elements will cause recursion in this method. In // order to propagate and preserve 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(getReaderContext(), root, parent); //验证xml namespace, BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI if (this.delegate.isDefaultNamespace(root)) { //获取Attribute String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } //解析前处理, 内容null 留个子类实现 preProcessXml(root); //解析 parseBeanDefinitions(root, this.delegate); //解析后处理, 内容null 留个子类实现 postProcessXml(root); this.delegate = parent; }
在doRegisterBeanDefinitions烦那个发中验证xml的namespace,最重要的方法是parseBeanDefinitions,parseBeanDefinitions方法进行了解析操作;
parseBeanDefinitions方法的源码:
/** * 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) { //验证xml namespace, BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI 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); } }
parseBeanDefinitions方法中已经开始对标签进行解析,区分默认标签和自定义标签,我们本次只对默认标签的源码进行解析,自定义标签自行DeBug,
parseDefaultElement方法的源码:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //解析import标签 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //解析alias标签并注册 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //解析bean标签并注册 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //解析beans标签 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
到这里我们可以看到,spring对import/bean/alias/beans的解析过程,对于beans的解析无法就是解析beans中的bean标签,spring直接又重新调用了doRegisterBeanDefinitions方法,我们接下来进行对bean标签的解析;
processBeanDefinition方法:
/** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //委托BeanDefinitionParserDelegate的parseBeanDefinitionElement方法进行元素解析并返回 //BeanDefinitionHolder实例,BeanDefinitionHolder已经包含了配置文件中的各种属性 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //当BeanDefinitionHolder返回不null的情况,弱存在默认标签下的子标签再有自定义的属性,还需要再次解析 if (bdHolder != null) { //解析默认标签中的自定义标签 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 进行实例注册注册操作是BeanDefinitionReaderUtisl.registerBeanDefinition进行处理 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)); } }
在processBeanDefinition方法中,spring做了两件事情:1:委托BeanDefinitionParserDelegate的parseBeanDefinitionElement方法进行元素解析并返回BeanDefinitionHolder实例,BeanDefinitionHolder已经包含了配置文件中的各种属性
2:通过上获得的BeanDefinitionHolder进行bean的注册操作,通BeanDefinitionReaderUtils.registerBeanDefinition方法;
通过delegate.parseBeanDefinitionElement方法进行xml解析:
/** * Parses the supplied {@code} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { //解析id属性 String id = ele.getAttribute(ID_ATTRIBUTE); //解析name属性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //分割name属性 List aliases = new ArrayList<>(); 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.isTraceEnabled()) { logger.trace("No XML "id" specified - using "" + beanName + "" as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //将信息封装到 beanDefinition中 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { //beanname不存在则使用默认规则创建 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.isTraceEnabled()) { logger.trace("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; }
在parseBeanDefinitionElement方法中做了三件事:1:解析id/name;
2:检查name的唯一性;
3:将信息封装到 beanDefinition中,接下来直接看parseBeanDefinitionElement方法;
parseBeanDefinitionElement源码:
/** * 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. */ @Nullable public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; //解析classname属性 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null; //解析parent属性 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { //创建用于承载属性的AbstractBeanDefinition类型的 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //解析bean的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); //提取description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //解析meta (元数据) parseMetaElements(ele, bd); //解析Lookup-method 书中53页有使用方法 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析replaced-method 书中55页有使用方法 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //构造函数 参数 //解析constructor-arg 书中replaced-method后边 parseConstructorArgElements(ele, bd); //解析Property 书中replaced-method后边 parsePropertyElements(ele, bd); //解析Qualifier 书中Property后边 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; }
通过上述代码我们可以看到这里首先是实例化了一个AbstractBeanDefinition来承载各种xml属性,接下来通过parseBeanDefinitionAttributes方法解析了xml中的各种你属性值,然后在解析lookUp-method(方法注入),replaced-method(替换方法或方法返回值),构造函数参数constructor-arg,property属性,Qualifier属性等;上述方法的源码就不一一展示了,无非都是通过Element进行解析;
接下来看真正注册的代码 BeanDefinitionReaderUtils.registerBeanDefinition
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { //beanName不可为空 Assert.hasText(beanName, "Bean name must not be empty"); //beanDefinition不可为空 Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { //校验 MethodOverrides,MethodOverrides在解析并组装beanDefinition时有提到 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } //beanDefinitionMap 存储实例的全局Map 使用ConcurrentHashMap 线程安全 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); //如果已经注册 处理内容 if (existingDefinition != null) { //是否覆盖 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean "" + beanName + "" with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean "" + beanName + "" with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean "" + beanName + "" with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { //判断是否已经至少创建过一次 使用AbstractBeanFactory.alreadyCreated来判断 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); ListupdatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // 仍处于启动注册阶段 // 注册 beanDefinitionMap 新实例 beanName + beanDefinition this.beanDefinitionMap.put(beanName, beanDefinition); // 增加beanDefinitionNames this.beanDefinitionNames.add(beanName); // 清除缓存 this.manualSingletonNames.remove(beanName); } // 清除缓存 this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
上述代码中首先验证了beanName和BeannDefinition不可为空,然后继续校验了MethodOverridesMethodOverrides在解析并组装beanDefinition时lookup-method和recpse-method的源码中有提到,继续判断beanDefinitionMap是否存在该bean,如果bean已经存在,通过allowBeanDefinitionOverriding属性判断是否可覆盖,反之则抛出异常;如果不存在则需要判断本次是否是第一次注册bean,如果是则初始化beanDefinitionMap后进行put操作,反之直接put beanDefinitionMap完成注册;
至此我们已经看完了整个XmlBeanFactory的xml解析和注册的源码部分,相信看本篇文章无法真正理解,还需要读者下载源码使用debug运行,再结合本篇文章的注释,相信会很容易理解,码字不易,转发请注明出处:https://blog.csdn.net/qq_3025...
博客地址:https://lantaogithub.github.io
博客地址:https://lantaogithub.github.io
简书:https://www.jianshu.com/u/bfb...
CSDN:https://blog.csdn.net/qq_3025...
开源中国:https://my.oschina.net/u/3948555
掘金:https://juejin.im/user/5c8c6f...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/76208.html
摘要:对于开发者来说,无疑是最常用也是最基础的框架之一。概念上的东西还是要提一嘴的用容器来管理。和是容器的两种表现形式。定义了简单容器的基本功能。抽象出一个资源类来表示资源调用了忽略指定接口的自动装配功能委托解析资源。 对于Java开发者来说,Spring无疑是最常用也是最基础的框架之一。(此处省略1w字吹Spring)。相信很多同行跟我一样,只是停留在会用的阶段,比如用@Component...
摘要:在上文中,我实现了一个很简单的和容器。比如,我们所熟悉的就是在这里将切面逻辑织入相关中的。初始化的工作算是结束了,此时处于就绪状态,等待外部程序的调用。其中动态代理只能代理实现了接口的对象,而动态代理则无此限制。 1. 背景 本文承接上文,来继续说说 IOC 和 AOP 的仿写。在上文中,我实现了一个很简单的 IOC 和 AOP 容器。上文实现的 IOC 和 AOP 功能很单一,且 I...
plantuml code @startuml xmlBeanFactory: XmlBeanFactory -> reader:XmlBeanDefinitionReader : 1: loadBeanDefinitions(resource) activate xmlBeanFactory: XmlBeanFactory activate reader:XmlBeanDefinitionRe...
摘要:动态地代理,可以猜测一下它的含义,在运行时动态地对某些东西代理,代理它做了其他事情。所以动态代理的内容重点就是这个。所以下一篇我们来细致了解下的到底是怎么使用动态代理的。 之前讲了《零基础带你看Spring源码——IOC控制反转》,本来打算下一篇讲讲Srping的AOP的,但是其中会涉及到Java的动态代理,所以先单独一篇来了解下Java的动态代理到底是什么,Java是怎么实现它的。 ...
摘要:概述约定大于配置的功力让我们如沐春风,在我之前写的文章从到也对比过和这两个框架,不过最终以超高的代码信噪比和易上手性让我们映像颇深。至于,我想在非时代大家应该不陌生吧,作用是配置容器,也即形式的容器的配置类所使用。 showImg(https://segmentfault.com/img/remote/1460000015822144); 概 述 SpringBoot 约定大于配置...
阅读 2268·2021-11-23 09:51
阅读 1094·2021-11-22 13:52
阅读 3589·2021-11-10 11:35
阅读 1163·2021-10-25 09:47
阅读 2940·2021-09-07 09:58
阅读 1038·2019-08-30 15:54
阅读 2792·2019-08-29 14:21
阅读 3002·2019-08-29 12:20