Spring IOC(二)容器初始化
本系列目录:
Spring IOC(一)概览
Spring IOC(二)容器初始化
Spring IOC(三)依赖注入
Spring IOC(四)总结
目录
一、ApplicationContext接口设计
二、深入源码,看IOC容器初始化
===========正文分割线===========
前面一篇概览了IOC容器的接口设计。
本文从ApplicationContext接口的一个实现类ClassPathXmlApplicationContext入手,分析容器初始化过程。先看一下ApplicationContext接口设计:
一、ApplicationContext接口设计
ApplicationContext是spring中较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,当有请求的时候分配bean。 另外,它增加了企业所需要的功能,比如,从属性文件解析文本信息和将事件传递给所指定的监听器。接口设计图如下:
,
ApplicationContext继承5个接口:
1.2个核心接口:
ListableBeanFactory:支持获取bean 工厂的所有bean实例
HierarchicalBeanFactory:支持继承关系
2.3个拓展接口:
MessageSource:提供国际化支持
ApplicationEventPublisher:支持事件驱动模型中的事件发布器,这些事件和Bean的生命周期的结合为Bean的管理提供了便利。
ResourcePatternResolver:资源解析器
常见实现类:
1.FileSystemXmlApplicationContext:从指定文件地址的加载xml定义的bean
2.ClassPathXmlApplicationContext:从类路径下载入xml定义的bean
3.XmlWebApplicationContext:web 应用程序的范围内载入xml定义的bean
二、深入源码,看IOC容器初始化
为了方便理解和追踪代码,使用常用实现类ClassPathXmlApplicationContext写了一个小例子,步骤如下:
1).在类路径下新建xml,定义一个bean,其中daoImpl就是bean的名字,spring.aop.xml.dao.impl.DaoImpl对应具体的一个pojo.
<bean id="daoImpl" class="spring.aop.xml.dao.impl.DaoImpl" />
2).main方法中直接载入xml,然后获取bean,最后执行bean实例的方法。
public static void main(String[] args) {
//源码入口,从类路径下读取xml
ApplicationContext ac1 = new ClassPathXmlApplicationContext("aop.xml");
Dao dao = (Dao)ac1.getBean("daoImpl");//根据名称获取Bean
dao.select();//执行Bean实例方法
}
下面我们就分析ClassPathXmlApplicationContext源码,来看看都做了什么。
2.1ClassPathXmlApplicationContext类图
DefaultResourceLoader,该类设置classLoader,并且将配置文件 封装为Resource文件。
AbstractApplicationContext,该类完成了大部分的IOC容器初始化工作,同时也提供了扩展接口留给子类去重载。该类的refresh()函数是核心初始化操作。
AbstractRefreshableApplicationContext,该类支持刷新BeanFactory。
AbstractRefreshableConfigApplicationContext,该类保存了配置文件路径
AbstractXmlApplicationContext:该类支持解析bean定义文件
最后ClassPathXmlApplicationContext:只提供了一个简单的构造函数
Spring 将类职责分开,形成职责链,每一层次的扩展 都只是添加了某个功能
然后父类定义大量的模板,让子类实现,父类层层传递到子类 直到某个子类重载了抽象方法。这里应用到了职责链设计模式和模板设计模式,IOC是个容器工厂设计模式。
2.2 回顾上面的小例子,new ClassPathXmlApplicationContext("aop.xml");这行代码做了什么?
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException { super(parent);//把ApplicationContext作为父容器,上述测试类中由于直接载入的xml,没有父容器所以实际传了null
setConfigLocations(configLocations);//替换${}后设置配置路径
if (refresh) {
refresh();//核心方法
}
}
ClassPathXmlApplicationContext的refresh()实际上就是调用了AbstractApplicationContext的refresh()方法。全方法被synchronized同步块锁住,源码如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证。
prepareRefresh(); //启动子类的refreshBeanFactory方法.解析xml
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //为BeanFactory配置容器特性,例如类加载器、事件处理器等.
prepareBeanFactory(beanFactory); try {
//设置BeanFactory的后置处理. 空方法,留给子类拓展用。
postProcessBeanFactory(beanFactory); //调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的.
invokeBeanFactoryPostProcessors(beanFactory); //注册Bean的后处理器, 在Bean创建过程中调用.
registerBeanPostProcessors(beanFactory); //初始化上下文中的消息源,即不同语言的消息体进行国际化处理
initMessageSource(); //初始化ApplicationEventMulticaster bean,应用事件广播器
initApplicationEventMulticaster(); //初始化其它特殊的Bean, 空方法,留给子类拓展用。
onRefresh(); //检查并向容器注册监听器Bean
registerListeners(); //实例化所有剩余的(non-lazy-init) 单例Bean.
finishBeanFactoryInitialization(beanFactory); //发布容器事件, 结束refresh过程.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} //销毁已经创建的单例Bean, 以避免资源占用.
destroyBeans(); //取消refresh操作, 重置active标志.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
//重置Spring的核心缓存
resetCommonCaches();
}
}
}
2.3 Resources定位
refresh方法中obtainFreshBeanFactory方法调用了refreshBeanFactory,该方法使用DefaultListableBeanFactory去定位resources资源
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {//创建并设置DefaultListableBeanFactory同时调用loadBeanDefinitions载入loadBeanDefinition
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);//核心方法
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
loadBeanDefinitions其具体实现在AbstractXmlApplicationContext中,定义了一个Reader作为入参执行载入过程:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为给定的bean工厂创建一个reader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);//核心方法
}
loadBeanDefinitions方法如下:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
getConfigResources采用模板方法设计模式,具体的实现由子类完成,实际上这里getConfigResources调用的就是子类ClassPathXmlApplicationContext的getConfigResources方法。ClassPathXmlApplicationContext继承了DefaultResourceLoader,具备了Resource加载资源的功能。至此完成了Resource定位!
2.4 BeanDefinition载入
这里支持2种模式:1.模板匹配多资源,生成Resource[]。2.载入单个资源url绝对地址,生成一个Resource
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();//获取ResourceLoader资源加载器
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
// 1.匹配模板解析 ClassPathXmlApplicationContext是ResourcePatternResolver接口的实例
if (resourceLoader instanceof ResourcePatternResolver) { try {//接口ResourcePatternResolver
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// 2.载入单个资源url绝对地址
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
loadBeanDefinitions最终调用XmlBeanDefinitionReader.doLoadBeanDefinitions(),如下:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {// 取得xml文件的Document,解析过程是由DocumentLoader完成,默认为DefaultDocumentLoader
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);// 启动对BeanDefinition的详细解析过程,这个解析会使用到spring的BEAN配置规则
}
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);
}
}
registerBeanDefinitions是按照spring的bean配置规则解析,源码如下:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 核心方法
return getRegistry().getBeanDefinitionCount() - countBefore;
}
至此就完成了BeanDefinition的载入,BeanDefinition的载入分为两个部分,
1.调用xml解析器得到的document对象,但是这个对象并没有按照spring的bean规则进行解析。
2.DefaultBeanDefinitionDocumentReader的registerBeanDefinitions按照Spring的Bean规则进行解析。
2.5 BeanDefinition解析和注册
registerBeanDefinitions方法调用了doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
// 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(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)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
} preProcessXml(root);
parseBeanDefinitions(root, this.delegate);// 从Document的根元素开始进行Bean定义的Document对象
postProcessXml(root); this.delegate = parent;
}
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);
}
} 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);
}
}
processBeanDefinition就是对bean标签的解析和注册
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 1.解析
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//代理去装饰:典型的装饰器模式
try {
// 2.向IOC容器注册Bean定义+bean工厂
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 3.触发注册事件: spring只提供了EmptyReaderEventListener空实现,如果需要你可以自定义
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
解析:parseBeanDefinitionElement方法就是具体的解析入口。解析elemnent->BeanDefinitionHolder,追踪parseBeanDefinitionElement:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);// 获取id
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);// 获取name 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;
}
好吧,parseBeanDefinitionElement才是核心方法,追踪:
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);
}// 这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 1.解析<bean>元素属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//2.解析description
//对各种BEAN元素信息进行解析
parseMetaElements(ele, bd);// 3.解析<meta>子元素
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//4.解析<lookup-method>子元素
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//5.解析<replaced-method>子元素 parseConstructorArgElements(ele, bd);//6.解析<constructor-arg>
parsePropertyElements(ele, bd);//7.解析<property>
parseQualifierElements(ele, bd);//8.解析<qualifier> 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;
}
经过这样逐层的分析,我们在xml文件中定义的BeanDefinition就被整个载入到IOC容器中,并在容器中建立了数据映射。这些数据结构可以以AbstractBeanDefinition为入口让IOC容器执行索引,查询和操作。
注册:registerBeanDefinition方法就是具体的注册入口。追踪registerBeanDefinition:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException { // Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//向IoC容器注册BeanDefinition // 如果解析的BeanDefinition有别名, 向容器为其注册别名.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
registerBeanDefinition具体实现类:DefaultListableBeanFactory.registerBeanDefinition方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
} BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
} if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
完成了BeanDefinition的注册,就完成了IOC容器的初始化过程。容器的作用就是对这些信息进行处理和维护,这些信息就是容器建立依赖反转的基础。
三、总结
本文先介绍ApplicationContext接口设计,再从其一个最常见实现类ClassPathXmlApplicationContext写了一个小例子,作为源码追踪的入口。
追踪了主要包括Resourse定位、BeanDefinition的载入、解析和注册3个模块。至此,容器初始化(Bean已生成)已完成,下一章我们看依赖注入的源码。
Spring IOC(二)容器初始化的更多相关文章
- Spring源码-IOC部分-容器初始化过程【2】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- Spring IoC bean 的初始化
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...
- Spring系列(五) 容器初始化过程源码
IoC/DI 的概念 容器是Spring的核心之一(另一个核心是AOP). 有了容器, IOC才可能实现. 什么使IoC? IoC就是将类自身管理的与其由依赖关系的对象的创建/关联和管理交予容器实现, ...
- Spring IOC 低级容器解析
1.IOC是什么 IOC-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不 ...
- Spring IOC 一——容器装配Bean的简单使用
下文:SpringIOC 二-- 容器 和 Bean的深入理解 写在前面 这篇文章去年写的,缘起于去年某段时间被领导临时"抓壮丁"般的叫过去做java开发,然后在网上找了一个 Sp ...
- Spring IOC之容器扩展点
一般来说,一个应用开发者不需要继承ApplicationContext实现类.取而代之的是,Spring IoC容器可以通过插入特殊的整合接口的实现来进行扩展.下面的几点将要讲述这些整合的接口. 1. ...
- Spring IOC之容器概述
1.SpringIOC容器和beans介绍 IOC的依赖注入是这样的,对象定义他们的依赖也就是他们需要在一起起作用的对象是通过构造器参数以及工厂方法的参数或者是当他们被构建或者是从工厂中返回时设置在对 ...
- [转]Spring IOC父子容器简介
通过HierarchicalBeanFactory接口,Spring的IoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,但父容器不能访问子容器的Bean.在容器内,Bean的 ...
- JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(6):Spring IOC容器学习(概念、作用、Bean生命周期)
一.IOC控制反转概念 控制反转(IOC)是一种通过描述(在Java中可以是XML或者是注解)并通过第三方去生产或获取特定对象的方式. 主动创建模式,责任在于开发者,而在被动模式下,责任归于Ioc容器 ...
- Spring源码-IOC部分-容器简介【1】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
随机推荐
- Apache Flink Quickstart
Apache Flink 是新一代的基于 Kappa 架构的流处理框架,近期底层部署结构基于 FLIP-6 做了大规模的调整,我们来看一下在新的版本(1.6-SNAPSHOT)下怎样从源码快速编译执行 ...
- web3.js
安装 别按照官网上面 npm install web3 下载,我已经吃过一次亏了 npm initnpm install ethereum/web3.js --save web3.isConn ...
- the import java.util.* cannot be resolve,怎么解决
我碰到这个问题是因为重装系统后,原先的JDK6换成了JDK7, Eclipse中的旧项目中jsp文件的此类import出现错误提示.在以下页面找到解决方案,专贴出来: http://www.myexc ...
- 浅谈 RxAndroid + Retrofit + Databinding
http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0131/3930.html 最近 RxAndroid .MVP.MVVM 一直是 And ...
- JAVA 语法2
1.算术运算符 运算符 运算规则 范例 结果 + 正号 +3 3 + 加 2+3 5 + 连接字符串 "中"+"国" "中国" - 负号 i ...
- Elasticsearch JavaApi
官网JavaApi地址:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search.html 博 ...
- ArcticCore重构-VALIDATE_%
基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5 基本问题 Arctic Core中使用了VALIDATE, VALIDATE_RV, VALIDATE_NO_RV ...
- hadoop中setup,cleanup,run和context讲解
hadoop 执行中的setup run cleanup context的作用1.简介1) setup(),此方法被MapReduce框架仅且执行一次,在执行Map任务前,进行相关变量或者资源的集中初 ...
- javascript 用函数语句和表达式定义函数的区别详解
通常我们会看到以下两种定义函数的方式: // 函数语句 function fn(str) { console.log(str); }; // 表达式定义 var fnx=function(str) { ...
- 阿里Java架构师谈谈架构和如何成为一个Java架构师
架构的定义 我们来看看软件架构的一般定义: 程序和计算系统软件体系结构是指系统的一个或多个结构. 该结构包括软件的构建,构建的外部可见属性以及它们之间的相互关系. 该体系结构不是可操作的软件. 具体来 ...