摘要:生成的两种方式通过反射调用构造函数通过优点依赖关系的管理被反转并交给容器,使复杂的依赖关系管理从应用中解放出来。
IOC概述
1、理解:
(1)控制反转。将生成对象的控制权交IOC容器,由容器生成依赖的对象。调用类只依赖接口,而不依赖具体的实现类,减少了耦合。在运行的时候,才由容器将具体的实例注入到调用类的对象中。
(2)依赖注入,就是向Ioc容器索要bean的过程。getBean是依赖注入的起点。依赖注入的过程是用户第一次向Ioc容器索要Bean时触发的。
(3)生成bean的两种方式
a、通过反射调用构造函数 b、通过CGLib
2、优点:
(1)依赖关系的管理被反转并交给容器,使复杂的依赖关系管理从应用中解放出来。
(2)代码解耦
3、启动过程(依赖注入的实现过程):
a、Resource寻找资源(XML文件形式的beanDefinition) b、将XML文件载入内存中,解析成org.springframework.beans.factory.config.BeanDefinition对象 c、将org.springframework.beans.factory.config.BeanDefinition对象注册到HashMap容器中 d、客户想Ioc容器索要bean,触发依赖注入基础使用
一、首先讲解依赖注入的3种方式:
1、set方式注入:
假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,然后创建SpringDao的set方法(这是ioc的注入入口):
package com.bless.springdemo.action; public class SpringAction { //注入对象springDao private SpringDao springDao; //一定要写被注入对象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void ok(){ springDao.ok(); } }
随后编写spring的xml文件,
2、构造器注入:
这种方式的注入是指带有参数的构造函数注入,看下面的例子,我创建了两个成员变量SpringDao和User,但是并未设置对象的set方法,所以就不能支持Set注入方式,这里的注入方式是在SpringAction的构造函数中注入,也就是说在创建SpringAction对象时要将SpringDao和User两个参数值传进来:
public class SpringAction { //注入对象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("构造方法调用springDao和user"); } public void save(){ user.setName("卡卡"); springDao.save(user); } }
在XML文件中同样不用
解决构造方法参数的不确定性,你可能会遇到构造方法传入的两参数都是同类型的,为了分清哪个该赋对应值,则需要进行一些小处理:
下面是设置index,就是参数位置:
另一种是设置参数类型:
3、接口注入:
ClassA依赖于InterfaceB,在运行期, InterfaceB 实例将由容器提供。
public class ClassA { private InterfaceB clzB; public Object doSomething(InterfaceB b) { clzB = b; return clzB.doIt(); } } …… }
二、Bean标签
1、scope属性:
(1)singleton:单例模式,即该bean对应的类只有一个实例;在spring 中是scope(作用范围)参数的默认值 ;
(2)prototype:表示每次从容器中取出bean时,都会生成一个新实例;相当于new出来一个对象;
(3)request:基于web,表示每次接受一个HTTP请求时,都会生成一个新实例;
(4)session:表示在每一个session中只有一个该对象.
(5)global session
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。
配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:
(6)自定义bean装配作用域:
在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定义,自定义自己的作用域只要实现该接口即可,下面给个实例:
我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:
publicclass MyScope implements Scope { privatefinal ThreadLocal threadScope = new ThreadLocal() { protected Object initialValue() { returnnew HashMap(); } }; public Object get(String name, ObjectFactory objectFactory) { Map scope = (Map) threadScope.get(); Object object = scope.get(name); if(object==null) { object = objectFactory.getObject(); scope.put(name, object); } return object; } public Object remove(String name) { Map scope = (Map) threadScope.get(); return scope.remove(name); } publicvoid registerDestructionCallback(String name, Runnable callback) { } public String getConversationId() { // TODO Auto-generated method stub returnnull; } }源码解析
一、IOC容器:
1、对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就是我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,比如说ApplicationContext。这样可以方便我们从不同的层面,不同的资源位置,不同的形式的定义信息来建立我们需要的IoC容器。
在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求,查看BeanFactory的源码:
public interface BeanFactory { //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象, //如果需要得到工厂本身,需要转义 String FACTORY_BEAN_PREFIX = "&"; //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。 Object getBean(String name) throws BeansException; //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。 Object getBean(String name, Class requiredType) throws BeansException; //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean boolean containsBean(String name); //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; //这里对得到bean实例的Class类型 Class getType(String name) throws NoSuchBeanDefinitionException; //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来 String[] getAliases(String name); }
2、容器加载流程解析:
这里我们以ClassPathXmlApplicationContext的初始化为例
(1)首先从容器构造函数入口:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { //这里是IoC容器的初始化过程,其初始化过程的大致步骤由AbstractApplicationContext来定义 refresh(); } }
(2)再看AbstractApplicationContext中refresh函数定义,这个方法包含了整个BeanFactory初始化的过程。这里使用到模板模式。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备这个上下文来刷新 prepareRefresh(); // 告诉子类刷新其beanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 准备将要在上下文中使用的bean工厂 prepareBeanFactory(beanFactory); try { // 允许在上下文子类中对bean工厂进行后处理 postProcessBeanFactory(beanFactory); // 调用 factory processors注册为上下文中的bean invokeBeanFactoryPostProcessors(beanFactory); // 注册 拦截bean创建的bean处理器 registerBeanPostProcessors(beanFactory); // 初始化此上下文的消息源 initMessageSource(); // 初始化此上下文的时间多播器 initApplicationEventMulticaster(); // 在特殊上下文子类中初始化其特殊的bean onRefresh(); // 检查监听器bean,并且注册它们 registerListeners(); // 初始化所有剩下的(非懒加载)单例 finishBeanFactoryInitialization(beanFactory); // 发布相应的事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 销毁已经创建的单例,以避免资源泄漏 destroyBeans(); // 重置active标志位 cancelRefresh(ex); // 抛出异常给调用者 throw ex; } finally { // 在Spring的核心中重置常见的自检缓存,因为我们可能不再需要单例对象的元数据了 resetCommonCaches(); } } }
(4)进入obtainFreshBeanFactory()函数,发现调用refreshBeanFactory(),而refreshBeanFactory()里面调用了loadBeanDefinitions()函数,该函数描述了加载bean定义的过程,最终会调用”具体的解析和注册过程“。
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 为给定的BeanFactory创建一个新的XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 使用此上下文的资源加载环境,去配置bean定义阅读器。 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 允许子类提供reader的自定义初始化,然后执行实际加载bean定义。 initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { // 调用XmlBeanDefinitionReader来载入bean定义信息。 reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } // XmlBeanDefinitionReader.java 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.getResource()); } 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 { 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); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //通过解析得到DOM,然后完成bean在IOC容器中的注册 Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } ....
我们看到先把定义文件解析为DOM对象,然后进行具体的注册过程:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 具体的注册过程,首先得到XmlBeanDefinitionReader,来处理xml的bean定义文件 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
(5)在BeanDefinitionDocumentReader中完成bean定义文件的解析和IOC容器bean的初始化。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } // 对配置文件(xml文件)进行解析 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)) { //这里是解析过程的调用,对缺省的元素进行分析比如bean元素 parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } 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)) { //这里对我们最熟悉的bean元素进行处理 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包含了具体的bean解析的过程。 // 把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是IOC容器的管理对象。 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 这里是向IOC容器注册,实际上是放到IOC容器的一个map里 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name "" + bdHolder.getBeanName() + """, ele, ex); } // 这里向IOC容器发送事件,表示解析和注册完成 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
(6)我们看到在parseBeanDefinition中对具体bean元素的解析式交给BeanDefinitionParserDelegate来完成的,下面我们看看解析完的bean是怎样在IOC容器中注册的:
在BeanDefinitionReaderUtils调用的是:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); //这是调用IOC来注册的bean的过程,需要得到BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 别名也是可以通过IOC容器和bean联系起来的进行注册 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
(7)我们看看XmlBeanFactory中的注册实现:
//--------------------------------------------------------------------- // 这里是IOC容器对BeanDefinitionRegistry接口的实现 //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { .....//这里省略了对BeanDefinition的验证过程 //先看看在容器里是不是已经有了同名的bean,如果有抛出异常。 Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { ........... } else { //把bean的名字加到IOC容器中去 this.beanDefinitionNames.add(beanName); } //这里把bean的名字和Bean定义联系起来放到一个HashMap中去,IOC容器通过这个Map来维护容器里的Bean定义信息。 this.beanDefinitionMap.put(beanName, beanDefinition); removeSingleton(beanName); }
这样就完成了Bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。
总结IOC容器初始化流程:1、初始化的入口在容器实现中的refresh()调用来完成
2、将bean定义信息载入IOC容器。使用的方法是loadBeanDefinition,其中的大致过程如下:
(1)通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统, URL等方式来定为资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的
(2)容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是XmlBeanDefinitionReader来解析bean的xml定义文件 - 实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示 - 这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关的方法 - 他们都是为处理BeanDefinitin服务的,IoC容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这由IOC实现 BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的 BeanDefinition的过程。这个HashMap是IoC容器持有bean信息的场所,以后对bean的操作都是围绕这个HashMap来实现的。
(3)然后我们就可以通过BeanFactory和ApplicationContext来享受到Spring IOC的服务了.
1、BeanFactory 指的是IOC容器的编程抽象,比如ApplicationContext, XmlBeanFactory等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定但Spring为我们提供了丰富的选择。
2、Factory bean 是一个可以在IOC容器中被管理的一个bean,是对各种处理过程和资源使用的抽象,Factory bean在需要时产生另一个对象,而不返回FactoryBean本省,我们可以把它看成是一个抽象工厂,对它的调用返回的是工厂生产的产品。所有的 Factory bean都实现特殊的org.springframework.beans.factory.FactoryBean接口,当使用容器中factory bean的时候,该容器不会返回factory bean本身,而是返回其生成的对象。Spring包括了大部分的通用资源和服务访问抽象的Factory bean的实现,其中包括:
对JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可以看成是具体的工厂,看成是SPRING为我们建立好的工厂。也就是说Spring通过使用抽象工厂模式为我们准备了一系列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在IOC容器里配置好就能很方便的使用了。
一、lazy-init延迟加载
1、执行原理:
lazy-init属性:为true的话,在Ioc容器初始化过程中,会对BeanDefinitionMap中所有的Bean进行依赖注入,这样在初始化过程结束后,容器执行getBean得到的就是已经准备好的Bean,不需要进行依赖注入。
2、优点:当应用第一次向容器索取所需的Bean时,容器不再需要对Bean进行初始化,直接从已经完成实例化的Bean中取出需要的bean,这样就提高了第一次获取Bean的性能。
二、BeanPostProcessor后置处理器:
1、BeanPostProcessor后置处理器是Spring IoC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器触发的Bean声明周期事件。后置处理器想容器注册以后,容器中管理的Bean就具备了接收IoC容器事件回调的能力。
2、BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean的配置文件中设置即可。
3、API解释:
public interface BeanPostProcessor { /** * Apply this BeanPostProcessor to the given new bean instance before any bean * initialization callbacks (like InitializingBean"s {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. */ //实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; /** * Apply this BeanPostProcessor to the given new bean instance after any bean * initialization callbacks (like InitializingBean"s {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. */ //实例化、依赖注入、初始化完毕时执行 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
三、自动装配:
1、概念:无须在Spring配置文件中描述javaBean之间的依赖关系(如配置
2、在Spring中,支持 5 自动装配模式。
(1)no – 缺省情况下,自动配置是通过“ref”属性手动设定
(2)byName – 根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。
(3)byType – 按数据类型自动装配。如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。
(4)constructor – 在构造函数参数的byType方式。
ApplicationContext容器中,Bean的生命周期流程如上图所示,流程大致如下:
1.首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化,
2.按照Bean定义信息配置信息,注入所有的属性,
3.如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id,
4.如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory,
5.如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext,
6.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法,
7.如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法,
8.如果Bean配置了init-method方法,则会执行init-method配置的方法,
9.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法,
10.经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,期生命周期就交给调用方管理了,不再是Spring容器进行管理了
11.容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法,
12.如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean的生命周期结束
参考:
http://www.iteye.com/topic/86339
http://blessht.iteye.com/blog...
https://blog.csdn.net/masterm...
https://blog.csdn.net/sugar_r...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69181.html
摘要:使用的好处知乎的回答不用自己组装,拿来就用。统一配置,便于修改。 前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工厂模式,总的来说还是非常值得的! 本来想的是刷完《Spring 实战 (第4版)》和《精通Spring4.x 企业应用开发实战》...
摘要:简介本篇文章是容器源码分析系列文章的最后一篇文章,本篇文章所分析的对象是方法,该方法用于对已完成属性填充的做最后的初始化工作。后置处理器是拓展点之一,通过实现后置处理器接口,我们就可以插手的初始化过程。 1. 简介 本篇文章是Spring IOC 容器源码分析系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bean 做最...
摘要:本文是容器源码分析系列文章的第一篇文章,将会着重介绍的一些使用方法和特性,为后续的源码分析文章做铺垫。我们可以通过这两个别名获取到这个实例,比如下面的测试代码测试结果如下本小节,我们来了解一下这个特性。 1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本。经过十几年的迭代,现在的 Spring 框架已经非常成熟了...
摘要:实例化时,发现又依赖于。一些缓存的介绍在进行源码分析前,我们先来看一组缓存的定义。可是看完源码后,我们似乎仍然不知道这些源码是如何解决循环依赖问题的。 1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的。在本篇文章中,我会首先向大家介绍一下什么是循环依赖。然后,进入源码分析阶段。为了更好的说明 Spring 解决循环依赖的办法,我将会从获取 bean 的方法getB...
摘要:在写完容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了天时间阅读了方面的源码。从今天开始,我将对部分的源码分析系列文章进行更新。全称是,即面向切面的编程,是一种开发理念。在中,切面只是一个概念,并没有一个具体的接口或类与此对应。 1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解。在写完 Spring IOC 容器源码分析系列...
阅读 5579·2021-11-24 10:25
阅读 2597·2021-11-16 11:44
阅读 3795·2021-10-11 11:09
阅读 3134·2021-09-02 15:41
阅读 3227·2019-08-30 14:14
阅读 2243·2019-08-29 14:10
阅读 2316·2019-08-29 11:03
阅读 1092·2019-08-26 13:47