1.IOC是什么

IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

想要理解IOC就要先了解博客之前的一篇文章《Java中类与类的关系》一文。实际上IOC处理的是关联(Association)这种关系。

谁控制了谁 通常情况下我们创建一个关联关系使用的是new关键字。在一个对象中创建另外一个对象。是程序主动去创建对象。而IOC是创建一个容器,使用容器来创建对象。即IOC容器控制了对象的创建。

谁被反转了 传统的应用程序是我们主动去new一个对象来获取外部对象,这叫正转。那什么叫反转呢,上一条我们讲到了对象的创建由容器完成,那么容器帮我们注入我们需要的对象。对象的创建获取由我们自己完成变成了由容器创建然后注入到我们创建好的引用中。即关联对象的获取被反转了。

2.IOC解决了什么问题

  首先我们说说IOC最大的好处。相信各位经常编码的朋友都有这种体验尤其是写Strus1、Struts2的时候项目中大量充斥着 XXX xxx = new XXX()这种代码 有的时候一个业务功能中相同的XXX xxx = new XXX()能出现十几次。这就造成了管理困难、配置困难。为了解决这种对象(资源)管理的困难,会引入一个第三方,由第三方管理所有的对象(资源),双方互相不依赖需要时只需要向第三方要就可以。所以IOC好处如下:

  • 第一,资源集中管理,实现资源的可配置和易管理。

  • 第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。

3.IOC实现原理

控制反转具体怎么用,就不说了spring大家不是用的666么

Spring IOC体系结构

1.BeanFactory

  Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:

javaBeanFactory接口,作为IOC容器老祖宗级别的接口,他定义了IOC的一些基本方法。

public interface BeanFactory {
//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义
String FACTORY_BEAN_PREFIX = "&"; Object getBean(String var1) throws BeansException; <T> T getBean(String var1, Class<T> var2) throws BeansException; Object getBean(String var1, Object... var2) throws BeansException; <T> T getBean(Class<T> var1) throws BeansException; <T> T getBean(Class<T> var1, Object... var2) throws BeansException; boolean containsBean(String var1); boolean isSingleton(String var1) throws NoSuchBeanDefinitionException; boolean isPrototype(String var1) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException; Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String var1);
}

我们可以看到这个接口定义的大部分是如何获取实例即getBean以及一些对比判断、真名列表等操作。

下面我们查看下其下属的三个继承接口ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory

ListableBeanFactory

定义了批量操作的方法

public interface ListableBeanFactory extends BeanFactory {
/**
* 检查这个BeanFactory是否包含给定名字的的bean定义。
* 不考虑这个工厂参与的任何层级关系,
* 忽略不是bean定义的所有通过其他方式注册的单例bean
*/
boolean containsBeanDefinition(String var1); /**
* 返回在此工厂中定义的bean数量。
* 不考虑这个工厂参与的任何层级关系,
* 忽略不是bean定义的所有通过其他方式注册的单例bean
*/
int getBeanDefinitionCount(); /**
* 返回此工厂中定义的所有bean的名字。
* 不考虑此工厂参与的所有层次关系,
* 忽略不是bean定义的所有通过其他方式注册的单例bean
* 如果此工厂没有bean定义,返回一个空的数组。
*/
String[] getBeanDefinitionNames(); String[] getBeanNamesForType(ResolvableType var1); String[] getBeanNamesForType(Class<?> var1); String[] getBeanNamesForType(Class<?> var1, boolean var2, boolean var3); <T> Map<String, T> getBeansOfType(Class<T> var1) throws BeansException; <T> Map<String, T> getBeansOfType(Class<T> var1, boolean var2, boolean var3) throws BeansException;
//通过指定的注解类型,获取所有那些还没有创建bean实例的名字。
String[] getBeanNamesForAnnotation(Class<? extends Annotation> var1);
//查找所有注解为指定类型的bean,返回一个bean名字与其对应实例的映射表。
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> var1) throws BeansException;
/**
* 查找指定bean的注解。
* 如果在指定bean自身上面没有找到,则遍历它实现的接口和他的超类。
*/
<A extends Annotation> A findAnnotationOnBean(String var1, Class<A> var2) throws NoSuchBeanDefinitionException;
}
HierarchicalBeanFactory

分层bean工厂



public interface HierarchicalBeanFactory extends BeanFactory {
//返回其父工厂,如果没有返回Null
BeanFactory getParentBeanFactory();
//返回当前bean工厂上下文是否存在给定bean名字的bean,忽略定义在其继承层次中的工厂上下文。
//containsBean方法与此方法是二选一的,都忽略其继承层次中的bean定义,只在当前层次中查找
boolean containsLocalBean(String var1);
}
AutowireCapableBeanFactory
/*
* BeanFactory接口的扩展,被那些能够实现自动匹配的工厂实现,提供针对已存在bean实例的服务。
*
* 此BeanFactory的子接口通常情况下不用于应用程序代码,
* 典型使用案例查看BeanFactory或者ListableBeanFactory
*
* 整合其他框架的代码是此接口优势所在,它可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
*
* 此接口没有被ApplicationContext实现,因为他几乎不(代表有)在程序代码中使用。
* 那也就是说他从一个application context上下文中也是可用的,
* 通过ApplicationContext的getAutowireCapableBeanFactory方法就很容易访问此接口
*
* 你也可通过实现BeanFactoryAware,通过它当运行在ApplicationContext暴露内部BeanFactory接口
* 的功能访问AutowireCapableBeanFactory,仅仅需要将BeanFactory转换为AutowireCapableBeanFactory
*/
public interface AutowireCapableBeanFactory extends BeanFactory {
int AUTOWIRE_NO = 0;
int AUTOWIRE_BY_NAME = 1;
int AUTOWIRE_BY_TYPE = 2;
int AUTOWIRE_CONSTRUCTOR = 3;
/** @deprecated */
@Deprecated
int AUTOWIRE_AUTODETECT = 4;
/**
* 创建给定类对象类型的新的bean实例。
* 完整初始化所创建bean,包含所有可应用的BeanPostProcessor BeanPostProcessors
* 注:此方法预期创建一个新的实例,填充有注解的属性和方法,同时应用所的bean标准初始化回调。
* 此方法并非通过传统的by-name或者by-type完成实例属性的自动注入,如果要使用
* 传统的这些方式,使用方法createBean(Class, int, boolean)
*/
<T> T createBean(Class<T> var1) throws BeansException; void autowireBean(Object var1) throws BeansException; Object configureBean(Object var1, String var2) throws BeansException; Object createBean(Class<?> var1, int var2, boolean var3) throws BeansException; Object autowire(Class<?> var1, int var2, boolean var3) throws BeansException; void autowireBeanProperties(Object var1, int var2, boolean var3) throws BeansException; void applyBeanPropertyValues(Object var1, String var2) throws BeansException; Object initializeBean(Object var1, String var2) throws BeansException; Object applyBeanPostProcessorsBeforeInitialization(Object var1, String var2) throws BeansException; Object applyBeanPostProcessorsAfterInitialization(Object var1, String var2) throws BeansException; void destroyBean(Object var1); <T> NamedBeanHolder<T> resolveNamedBean(Class<T> var1) throws BeansException; Object resolveDependency(DependencyDescriptor var1, String var2) throws BeansException; Object resolveDependency(DependencyDescriptor var1, String var2, Set<String> var3, TypeConverter var4) throws BeansException;
}

在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。

而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition

2.AliasRegistry

该接口用于定义bean别名的增删改查

public interface AliasRegistry {
//给该name的bean定义一个别名
void registerAlias(String var1, String var2);
//删除别名
void removeAlias(String var1);
//判断name是否是已经注册的别名
boolean isAlias(String var1);
//返回该name注册的所有的别名
String[] getAliases(String var1);
}

该接口有一个接口拓展BeanDefinitionRegistry和一个实现类SimpleAliasRegistry

BeanDefinitionRegistry

该类的作用主要是向注册表中注册 BeanDefinition 实例,完成 注册的过程。

public interface BeanDefinitionRegistry extends AliasRegistry {

    // 关键 -> 往注册表中注册一个新的 BeanDefinition 实例
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException; // 移除注册表中已注册的 BeanDefinition 实例
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 从注册中取得指定的 BeanDefinition 实例
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 判断 BeanDefinition 实例是否在注册表中(是否注册)
boolean containsBeanDefinition(String beanName); // 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
String[] getBeanDefinitionNames(); // 返回注册表中 BeanDefinition 实例的数量
int getBeanDefinitionCount(); // beanName(标识)是否被占用
boolean isBeanNameInUse(String beanName); }
SimpleAliasRegistry

实现对别名的增删改等操作

public class SimpleAliasRegistry implements AliasRegistry {
//这里定义了一个用于存放别名的Map、使用了线程安全的Map
private final Map<String, String> aliasMap = new ConcurrentHashMap(16); public SimpleAliasRegistry() {
}
//注册别名
public void registerAlias(String name, String alias) {
//断言非空检查
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
//如果别名和名称相同则移除别名。这种别名没有意义
if (alias.equals(name)) {
this.aliasMap.remove(alias);
} else {
//检查别名是否存在
String registeredName = (String)this.aliasMap.get(alias);
//如果存在
if (registeredName != null) {
//判断别名是否已经注册过
if (registeredName.equals(name)) {
return;
}
//判断别名是否允许重写
if (!this.allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
}
}
//循环检查别名
this.checkForAliasCircle(name, alias);
//插入别名
this.aliasMap.put(alias, name);
} }
//是否允许别名覆盖 默认允许。
//注意这里使用的是钩子方法 可以在子类中重写该方法以改变操作方式
protected boolean allowAliasOverriding() {
return true;
}
//遍历别名列表检查是否存在该种名称和别名对
public boolean hasAlias(String name, String alias) {
Iterator var3 = this.aliasMap.entrySet().iterator(); Entry entry;
String registeredName;
do {
if (!var3.hasNext()) {
return false;
} entry = (Entry)var3.next();
registeredName = (String)entry.getValue();
} while(!registeredName.equals(name)); String registeredAlias = (String)entry.getKey();
return registeredAlias.equals(alias) || this.hasAlias(registeredAlias, alias);
}
//移除该别名
public void removeAlias(String alias) {
String name = (String)this.aliasMap.remove(alias);
if (name == null) {
throw new IllegalStateException("No alias '" + alias + "' registered");
}
}
//遍历是否存在别名
public boolean isAlias(String name) {
return this.aliasMap.containsKey(name);
}
//获取该名称所有的别名
public String[] getAliases(String name) {
List<String> result = new ArrayList();
Map var3 = this.aliasMap;
//这里加锁是为了防止迭代出现异常。ConcurrentHashMap的迭代器并不是线程安全的。
synchronized(this.aliasMap) {
this.retrieveAliases(name, result);
}
return StringUtils.toStringArray(result);
}
//将别名存入一个list用于遍历
private void retrieveAliases(String name, List<String> result) {
Iterator var3 = this.aliasMap.entrySet().iterator(); while(var3.hasNext()) {
Entry<String, String> entry = (Entry)var3.next();
String registeredName = (String)entry.getValue();
if (registeredName.equals(name)) {
String alias = (String)entry.getKey();
result.add(alias);
//这里强调下这里的递归使用时为了防止漏掉别名的别名而存在的。
this.retrieveAliases(alias, result);
}
} }
//解析配置文件并且配置别名。
public void resolveAliases(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
Map var2 = this.aliasMap;
//锁住map,同上 迭代器线程不安全
synchronized(this.aliasMap) {
//迭代该元素
Map<String, String> aliasCopy = new HashMap(this.aliasMap);
Iterator var4 = aliasCopy.keySet().iterator(); while(var4.hasNext()) {
//获取一个别名
String alias = (String)var4.next();
//获取这个别名的标准名
String registeredName = (String)aliasCopy.get(alias);
//读取配置中别名信息
String resolvedAlias = valueResolver.resolveStringValue(alias);
//读取配置中标准名的信息
String resolvedName = valueResolver.resolveStringValue(registeredName);
//如果解析后的别名或者canonicalName为空或者是别名与canonicalName相同,则移除.说明该条别名无效了。
//如果原始名和别名不同 进入下一步判断
if (resolvedAlias != null && resolvedName != null && !resolvedAlias.equals(resolvedName)) {
//如果解析后的canonicalName和现在Map中的canonicalName不同,则替换。
if (!resolvedAlias.equals(alias)) {
String existingName = (String)this.aliasMap.get(resolvedAlias);
//查看内部Map中以解析后的别名为key的项,如果不存在,则检查完循环引用后删除原始别名,添加解析后的别名.如果项存在,且存在项的value和解析后的name相同,只用将以原始aliase为key的entity移除即可
if (existingName != null) {
//如果存在项的value和解析后的name不同,则说明解析后的aliase已被占用了,则抛出IllegalStateException。
if (!existingName.equals(resolvedName)) {
throw new IllegalStateException("Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias + "') for name '" + resolvedName + "': It is already registered for name '" + registeredName + "'.");
} this.aliasMap.remove(alias);
break;
} this.checkForAliasCircle(resolvedName, resolvedAlias);
this.aliasMap.remove(alias);
this.aliasMap.put(resolvedAlias, resolvedName);
} else if (!registeredName.equals(resolvedName)) {
this.aliasMap.put(alias, resolvedName);
}
} else {
this.aliasMap.remove(alias);
}
} }
}
//循环检查别名是否存在
protected void checkForAliasCircle(String name, String alias) {
if (this.hasAlias(alias, name)) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': Circular reference - '" + name + "' is a direct or indirect alias for '" + alias + "' already");
}
} //返回一个规范的名称
public String canonicalName(String name) {
String canonicalName = name; String resolvedName;
do {
resolvedName = (String)this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
} while(resolvedName != null); return canonicalName;
}
}

钩子方法

另外需要了解下容器中到底存了什么的疑问就要看另外一个接口

BeanDefinition

容器中具体存在的就是 BeanDefinition

bean definition 存储bean类的定义信息的对象

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
//bean类型 单例 原型
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
//Bean角色
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
//父类名称
void setParentName(String var1); String getParentName();
//类名
void setBeanClassName(String var1); String getBeanClassName();
//作用域
void setScope(String var1); String getScope();
//懒加载
void setLazyInit(boolean var1); boolean isLazyInit();
//该类依赖名称
void setDependsOn(String... var1); String[] getDependsOn();
//返回这个bean是否是自动装入其他bean的候选者。
void setAutowireCandidate(boolean var1);
//返回这个bean是否是主要的autowire候选者。如果这个值对于多个bean中的一个bean是正确的
boolean isAutowireCandidate(); void setPrimary(boolean var1); boolean isPrimary();
//返回设置 工厂名
void setFactoryBeanName(String var1); String getFactoryBeanName();
/*
*指定工厂方法(如果有的话)。这个方法将被调用
     *构造函数参数,或者如果没有指定任何参数。
     *方法将在指定的工厂bean上调用,如果有的话,
     *或者作为本地bean类的静态方法。
*/
void setFactoryMethodName(String var1); String getFactoryMethodName(); ConstructorArgumentValues getConstructorArgumentValues(); MutablePropertyValues getPropertyValues(); boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); int getRole(); String getDescription(); String getResourceDescription(); BeanDefinition getOriginatingBeanDefinition();
}

3.SingletonBeanRegistry

//创建单例模式的对象注册接口

public interface SingletonBeanRegistry {
void registerSingleton(String var1, Object var2); Object getSingleton(String var1); boolean containsSingleton(String var1); String[] getSingletonNames(); int getSingletonCount(); Object getSingletonMutex();
}

扯了这么长时间的淡 我们来说说真正可以作为容器使用的DefaultListableBeanFactory。这可是所有spring容器的祖容器。也是整个spring IOC的核心中的核心

4.DefaultListableBeanFactory

继承关系图

偷懒了用IDEA生成的

可以说这个类关系图是对前面所有类的一个总结。在这里可以清晰看到各种类的关系。

DefaultListableBeanFactory其实要实现的功能就是以list集合的方式操作bean。为啥要分这么多接口呢,可能为了接口拓展方便。这实际上是面向接口编程的思想。

注意:

1.我们要储存的是bean的定义,而非实例。

分段代码解析

我们就从功能概述的8个功能来分析DefaultListableBeanFactory

下一章将解释下容器的创建过程。这里大概讲解下。首先在访问bean之前,是要通过配置文件或者注解啥的注册所有的bean。然后就鞥在容器中获取各种bean了

1.成员变量
@Nullable
private static Class<?> javaxInjectProviderClass; static {
try {
javaxInjectProviderClass =
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
javaxInjectProviderClass = null;
}
}

public interface Provider接口

Provider 用于提供类型 T 的实列。Provider 是一般情况是由注入器实现的。对于任何可注入的 T 而言,您也可以注入 Provider。与直接注入 T 相比,注入 Provider 使得:

可以返回多个实例。

实例的返回可以延迟化或可选

打破循环依赖。

可以在一个已知作用域的实例内查询一个更小作用域内的实例。

2.成员变量解析
//从序列化ID映射到工厂实例
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
new ConcurrentHashMap<>(8); //此工厂的可选ID,用于序列化目的
@Nullable
private String serializationId; //是否允许重新注册具有相同名称的不同定义
private boolean allowBeanDefinitionOverriding = true; //是否允许饿加载,即使是懒初始化bean
private boolean allowEagerClassLoading = true; //依赖关系列表和数组的可选OrderComparator
@Nullable
private Comparator<Object> dependencyComparator; //用于检查bean定义是否为自动导向候选项的解析器
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver(); //从依赖类型映射到相应的自动装载值
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16); //通过bean名称键入的bean定义对象的映射
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); //由独立类型键入的单例和非单例bean名称的映射
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64); //单例bean名称的映射,由依赖类型键入
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64); //注册顺序中的bean定义名称列表
private volatile List<String> beanDefinitionNames = new ArrayList<>(256); //按注册顺序人工注册的单例名单
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16); //冻结配置时缓存的bean定义名称数组
@Nullable
private volatile String[] frozenBeanDefinitionNames; //是否可以缓存所有bean的bean定义元数据
private volatile boolean configurationFrozen = false;
3.构造方法
//默认构造方法
public DefaultListableBeanFactory() {
super();
} //创建一个带父类的实例
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
4.beanFactory实现

在DefaultListableBeanFactory中实现了类型相关的bean。

部分在AbstractAutowireCapableBeanFactory中,实现了工厂接口中的其他功能

  1. 获取bean

    装载bean我们会在下一章讲解。获取bean是beanFactory主要核心定义的功能。

    beanFactory中 getbean返回的是一个bean实例,DefaultListableBeanFactory返回的不是bean的实例而是一个bean实例和bean名称存储对象
public class NamedBeanHolder<T> implements NamedBean {

	private final String beanName;

	private final T beanInstance;
}

第一种 通过类型获取bean

注意:这里的单例和单例模式里的单例并不能画等号。这里的单例是指一个bean只有一个实例。

@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
} @Override
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
//通过一个方法获取了一个NamedBeanHolder对象
//在本容器中寻找是否有该Bean
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
//在父容器中寻找是否有该bean,父类的父类容器中寻找如果没有则抛出异常
BeanFactory parent = getParentBeanFactory();
if (parent != null) {
return (args != null ? parent.getBean(requiredType, args) : parent.getBean(requiredType));
}
throw new NoSuchBeanDefinitionException(requiredType);
}

在本级容器中解析该类型bean并且返回

首先先去allBeanNamesByType和singletonBeanNamesByType查找是否有该类型的beans。

@SuppressWarnings("unchecked")
@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
String[] candidateNames = getBeanNamesForType(requiredType);
//如果大于一个beans实例,将所有bean装入autowireCandidates中
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
//如果等于一个元素则直接返回该实例和实例名
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, getBean(beanName, requiredType, args));
}
else if (candidateNames.length > 1) {
Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
candidates.put(beanName, getType(beanName));
}
}
//在给定的bean列表中寻找合格的主要bean
String candidateName = determinePrimaryCandidate(candidates, requiredType);
//如果没有合格的主要候选人 则选择优先级最高的候选bean
if (candidateName == null) {
candidateName = determineHighestPriorityCandidate(candidates, requiredType);
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType, args);
}
//选出则返回
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
//选不出来 抛出异常
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
} return null;
}

第二种 通过beanName获取bean

public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
} */
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name);
Object bean; //检查单例缓存中是否存在bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
//防止循环引用
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
} //当前容器没有则向上级容器寻找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
} if (!typeCheckOnly) {
markBeanAsCreated(beanName);
} try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//保证当前bean依赖的bean的初始化。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
} // 创建单例bean实例。并放入缓存
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) { //明确从单身缓存中删除实例:它可能已放在那里
//通过创建过程热切希望获得循环参考解析。
//还删除接收到bean的临时引用的任何bean。
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//创建原型实例 并放入缓存
else if (mbd.isPrototype()) { Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
} // 检查所需的类型是否与实际bean实例的类型相匹配。
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
5.工厂嵌套 HierarchicalBeanFactory实现

父容器的实例就保存在AbstractBeanFactory中,直接返回就好。父类容易可以通过子类构造方法传入

  //返回父类容器
public BeanFactory getParentBeanFactory() {
return this.parentBeanFactory;
}
//忽略层级关系只检查当前容器是否有该名称的bean
public boolean containsLocalBean(String name) {
String beanName = transformedBeanName(name);
return ((containsSingleton(beanName) || containsBeanDefinition(beanName)) &&
(!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName)));
}
6.自动装配AutowireCapableBeanFactory实现

类加载机制 类加载器虽然只用于实现类的加载动作,但是对于任意一个类,都需要由加载它的类加载器和这个类本身共同确立其在Java虚拟机中的唯一性。通俗的说,JVM中两个类是否“相等”,首先就必须是同一个类加载器加载的,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要类加载器不同,那么这两个类必定是不相等的。

RootBeanDefinition 是BeanDefinition的一个常用实现类。它对应一般性的元素标签.

BeanWrapper 是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器,由于BeanWrapper接口是PropertyAccessor的子接口,因此其也可以设置以及访问被包装对象的属性值。BeanWrapper大部分情况下是在spring ioc内部进行使用,通过BeanWrapper,spring ioc容器可以用统一的方式来访问bean的属性。用户很少需要直接使用BeanWrapper进行编程。

自动装配的方法大部分都是在AbstractAutowireCapableBeanFactory中实现的

主要功能是创建bean(通过注册信息BeanDefinition)、注入bean、配置bean等功能

@Override
@SuppressWarnings("unchecked")
public <T> T createBean(Class<T> beanClass) throws BeansException {
//使用原型bean定义,避免将bean注册为从属bean。
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
//判断是否缓存过
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
//通过bean名称和bean定义创建一个bean实例
return (T) createBean(beanClass.getName(), bd, null);
}
//使用指定的自动注入策略实例化给定类的新bean实例。
@Override
public void autowireBean(Object existingBean) {
//使用非单例bean定义,以避免将bean注册为从属bean。
RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), getBeanClassLoader());
//将传入的bean包装一下包装其变为可以配置的状态
BeanWrapper bw = new BeanWrapperImpl(existingBean);
//初始化bean
initBeanWrapper(bw);
populateBean(bd.getBeanClass().getName(), bd, bw);
}
//初始化一个bean
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
//创建一个bean
registerCustomEditors(bw);
}
//注册一个bean
protected void registerCustomEditors(PropertyEditorRegistry registry) {
PropertyEditorRegistrySupport registrySupport =
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
if (registrySupport != null) {
registrySupport.useConfigValueEditors();
}
if (!this.propertyEditorRegistrars.isEmpty()) {
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
try {
registrar.registerCustomEditors(registry);
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
"] failed because it tried to obtain currently created bean '" +
ex.getBeanName() + "': " + ex.getMessage());
}
onSuppressedException(ex);
continue;
}
}
throw ex;
}
}
}
if (!this.customEditors.isEmpty()) {
this.customEditors.forEach((requiredType, editorClass) ->
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
}
}
//配置给定的原始bean:autowiring bean属性,应用bean属性值,应用工厂回调,例如{setCodeBeanName}
//和setBeanFactory}以及应用所有bean后期处理器
@Override
public Object configureBean(Object existingBean, String beanName) throws BeansException {
markBeanAsCreated(beanName);
BeanDefinition mbd = getMergedBeanDefinition(beanName);
RootBeanDefinition bd = null;
if (mbd instanceof RootBeanDefinition) {
RootBeanDefinition rbd = (RootBeanDefinition) mbd;
bd = (rbd.isPrototype() ? rbd : rbd.cloneBeanDefinition());
}
if (bd == null) {
bd = new RootBeanDefinition(mbd);
}
if (!bd.isPrototype()) {
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(ClassUtils.getUserClass(existingBean), getBeanClassLoader());
}
BeanWrapper bw = new BeanWrapperImpl(existingBean);
//使用在该工厂注册的自定义编辑器初始化给定的BeanWrapper。 调用将创建和填充bean实例的BeanWrappers。
initBeanWrapper(bw);
//使用bean定义中的属性值在给定的BeanWrapper中填充bean实例。
populateBean(beanName, bd, bw);
//初始化给定的bean实例,应用工厂回调以及init方法和bean后期处理器。
return initializeBean(beanName, existingBean, bd);
}
7.集合操作ListableBeanFactory实现

主要是容器中是否有该实例、一共有几个实例、每个实例定义名称、实例的类型、依据类型获取bean列表等功能等一些集合操作

我挑一部分讲解下。

ResolvableType 在spring框架中需要反射的时候,为了不丢失泛型信息,通常都会使用ResolvableType封装所有的类型。

  //当前容器是否存在bean
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
//容器中bean的数量
@Override
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
//bean定义名称
//在初始化容器的时候就会添加
@Override
public String[] getBeanDefinitionNames() {
String[] frozenNames = this.frozenBeanDefinitionNames;
if (frozenNames != null) {
return frozenNames.clone();
}
else {
return StringUtils.toStringArray(this.beanDefinitionNames);
}
} //依据类型获取beannames
@Override
public String[] getBeanNamesForType(ResolvableType type) {
return doGetBeanNamesForType(type, true, true);
} @Override
public String[] getBeanNamesForType(@Nullable Class<?> type) {
return getBeanNamesForType(type, true, true);
} @Override
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
8.容器配置 ConfigurableBeanFactory实现

当前容器设置父容器、设置获取类加载器、设置获取零时类加载器、设置bean创建期间的注册参数、类型转换器、添加处理流程、设置生效范围、提供与此工厂相关的安全访问控制上下文、复制其他工厂的配置、注册别名、解析别名、获取bean定义文件、获取bean依赖、销毁bean等功能。主要是一些容器相关的配置设置。

这些配置功能大部分的实现不是很难,就不全部介绍了。下面是列举了一部分实现在AbstractBeanFactory实现的。


@Override
public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {
if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
}
this.parentBeanFactory = parentBeanFactory;
} @Override
public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) {
this.beanClassLoader = (beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader());
} @Override
@Nullable
public ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
} @Override
public void setTempClassLoader(@Nullable ClassLoader tempClassLoader) {
this.tempClassLoader = tempClassLoader;
} @Override
@Nullable
public ClassLoader getTempClassLoader() {
return this.tempClassLoader;
} @Override
public void setCacheBeanMetadata(boolean cacheBeanMetadata) {
this.cacheBeanMetadata = cacheBeanMetadata;
} @Override
public boolean isCacheBeanMetadata() {
return this.cacheBeanMetadata;
} @Override
public void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver) {
this.beanExpressionResolver = resolver;
} @Override
@Nullable
public BeanExpressionResolver getBeanExpressionResolver() {
return this.beanExpressionResolver;
} @Override
public void setConversionService(@Nullable ConversionService conversionService) {
this.conversionService = conversionService;
} @Override
@Nullable
public ConversionService getConversionService() {
return this.conversionService;
} @Override
public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) {
Assert.notNull(registrar, "PropertyEditorRegistrar must not be null");
this.propertyEditorRegistrars.add(registrar);
} public Set<PropertyEditorRegistrar> getPropertyEditorRegistrars() {
return this.propertyEditorRegistrars;
} @Override
public void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
Assert.notNull(requiredType, "Required type must not be null");
Assert.notNull(propertyEditorClass, "PropertyEditor class must not be null");
this.customEditors.put(requiredType, propertyEditorClass);
} @Override
public void copyRegisteredEditorsTo(PropertyEditorRegistry registry) {
registerCustomEditors(registry);
} public Map<Class<?>, Class<? extends PropertyEditor>> getCustomEditors() {
return this.customEditors;
} @Override
public void setTypeConverter(TypeConverter typeConverter) {
this.typeConverter = typeConverter;
} @Nullable
protected TypeConverter getCustomTypeConverter() {
return this.typeConverter;
} @Override
public TypeConverter getTypeConverter() {
TypeConverter customConverter = getCustomTypeConverter();
if (customConverter != null) {
return customConverter;
}
else {
// Build default TypeConverter, registering custom editors.
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.setConversionService(getConversionService());
registerCustomEditors(typeConverter);
return typeConverter;
}
} @Override
public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
this.embeddedValueResolvers.add(valueResolver);
} @Override
public boolean hasEmbeddedValueResolver() {
return !this.embeddedValueResolvers.isEmpty();
} @Override
@Nullable
public String resolveEmbeddedValue(@Nullable String value) {
if (value == null) {
return null;
}
String result = value;
for (StringValueResolver resolver : this.embeddedValueResolvers) {
result = resolver.resolveStringValue(result);
if (result == null) {
return null;
}
}
return result;
} @Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
} @Override
public int getBeanPostProcessorCount() {
return this.beanPostProcessors.size();
}

使用示例

编写一个配置文件

<?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-2.5.xsd">
<bean id="dog" class="com.yanlong.springOriRead.Dog"></bean>
</beans>

实体类

public class Dog {

	public void shout() {
System.out.println("wang wang wang!");
}
}

将实体类放入容器并且从容器中调用bean的方法

public class AutoWire {
public static void main(String[] args) {
//读取配置文件
ClassPathResource classPathResource = new ClassPathResource("beans.xml");
//创建容器
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
//Xmlbean定义读取工具
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
//读取配置文件中的beans
xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
//调用
System.out.println("numbers: " + defaultListableBeanFactory.getBeanDefinitionCount());
((Dog)defaultListableBeanFactory.getBean("dog")).shout();
}
}

4.总结

由DefaultListableBeanFactory可以看出实际上这个庞大功能的容器都是通过一层一层的接口不断添加新功能实现的。符合了最小接口原则。代码虽然庞大但是结构非常清晰。

下面总结下

接口功能

BeanFactory接口 是Spring的最根的接口,类的工厂接口。

HierarchicalBeanFactory接口 是在继承BeanFactory的基础上,实现BeanFactory的父子关系。

AutowireCapableBeanFactory接口 是在继承BeanFactory的基础上,实现Bean的自动装配功能

ListableBeanFactory接口 是在继承BeanFactory的基础上,实现Bean的list集合操作功能。

ConfigurableBeanFactory接口 是在继承HierarchicalBeanFactory的基础上,实现BeanFactory的全部配置管理功能.

SingletonBeanRegistry接口 是单例bean的注册接口.

ConfigurableListableBeanFactory接口 是继承AutowireCapableBeanFactory,ListableBeanFactory,ConfigurableBeanFactory三个接口的一个综合接口。外观模式。

AliasRegistry接口 是别名注册接口,

SimpleAliasRegistry类 是简单的实现别名注册接口的类。

DefaultSingletonBeanRegistry 是默认的实现SingletonBeanRegistry接口的类,同时,继承类SimpleAliasRegistry 。

FactoryBeanRegistrySupport 是实现FactoryBean注册的功能实现。继承类DefaultSingletonBeanRegistry 。

AbstractBeanFactory 是部分实现接口ConfigurableBeanFactory,并继承类FactoryBeanRegistrySupport 。又是一个外观模式。

AbstractAutowireCapableBeanFactory 是实现接口AutowireCapableBeanFactory,并继承类 AbstractBeanFactory 。

DefaultListableBeanFactory 实现接口 ConfigurableListableBeanFactory、BeanDefinitionRegistry(bean定义的注册接口), 并继承AbstractAutowireCapableBeanFactory,实现全部类管理的功能。

容器功能概述
  1. 可以实现一个bean工厂类用于创建bean
  2. 可以实现多层次工厂嵌套
  3. 可以实现自动装配功能
  4. 可以实现集合操作功能
  5. 可以实现配置管理功能呢
  6. 可以实现单例、原型bean注册功能
  7. 可以实现bean别名注册功能
  8. 可以实现bean定义注册功能
容器运行流程
  1. 利用ClassPathResource读取配置文件
  2. 创建容器实例。
  3. 创建读取工具实例XmlBeanDefinitionReader将容器实例作为参数传入。
  4. 利用读取工具XmlBeanDefinitionReader读取配置文件对象ClassPathResource。
  5. 容器初始化完成、调用功能。

Spring IOC 低级容器解析的更多相关文章

  1. Spring IOC设计原理解析:本文乃学习整理参考而来

    Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...

  2. Spring IoC源码解析之invokeBeanFactoryPostProcessors

    一.Bean工厂的后置处理器 Bean工厂的后置处理器:BeanFactoryPostProcessor(触发时机:bean定义注册之后bean实例化之前)和BeanDefinitionRegistr ...

  3. Spring IoC源码解析之getBean

    一.实例化所有的非懒加载的单实例Bean 从org.springframework.context.support.AbstractApplicationContext#refresh方法开发,进入到 ...

  4. Spring系列(三):Spring IoC源码解析

    一.Spring容器类继承图 二.容器前期准备 IoC源码解析入口: /** * @desc: ioc原理解析 启动 * @author: toby * @date: 2019/7/22 22:20 ...

  5. Spring IoC 自定义标签解析

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...

  6. Spring IoC源码解析——Bean的创建和初始化

    Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...

  7. Spring IOC之容器扩展点

    一般来说,一个应用开发者不需要继承ApplicationContext实现类.取而代之的是,Spring IoC容器可以通过插入特殊的整合接口的实现来进行扩展.下面的几点将要讲述这些整合的接口. 1. ...

  8. Spring IOC 源码解析(持续)

    如何查看源码 Spring源码下载https://github.com/spring-projects/spring-framework/tags?after=v3.1.0.RC1 eclipse关联 ...

  9. Spring IOC初始化深度解析

    1.前言 本文是基于JAVA配置方法对Spring IOC进行分析,掌握Spring IOC初始化流程对于我们更好的使用Spring.学习Spring还是很有帮助的,本文所使用的的Spring版本为5 ...

随机推荐

  1. docker存储与网络

    目录 Docker存储 挂载主机目录 创建一个数据卷 挂载一个宿主机目录作为数据卷 数据卷容器 创建一个数据卷容器 利用数据卷容器迁移数据 删除数据盘 Docker网络 简介 bridge网络 bri ...

  2. 计算机网络原理和OSI模型与TCP模型

    计算机网络原理和OSI模型与TCP模型 一.计算机网络的概述 1.计算机网络的定义 计算机网络是一组自治计算机的互连的集合 2.计算机网络的基本功能 a.资源共享 b.分布式处理与负载均衡 c.综合信 ...

  3. JAVA记录-JDBC介绍

    JDBC(Java DataBase Connection),java数据库连接,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成 ...

  4. C# 多线程辅助类实现多任务

    1)首先实现一个多线程的辅助类,代码如下: public class ThreadMulti { public delegate void DelegateComplete(); public del ...

  5. Git服务器,仓库的hook监控

    简单应用场景:代码提交到git仓库,仓库监控到变化的jar包,然后把变化的jar包推到私服maven仓库. Git预定义了触发时机: ClientSide hooks: 1 pre-commit,当执 ...

  6. CF418D Big Problems for Organizers

    传送门 题意,给一棵树,每次给两个点\(x,y\),求\(\max_{i=1}^{n}(\min(di_{x,i},di_{y,i}))\) 看std看了好久 以下是一个优秀的在线做法,\(O(nlo ...

  7. Java9都快发布了,Java8的十大新特性你了解多少呢?

    Java 9预计将于今年9月份发布,这是否会是一次里程碑式的版本,我们拭目以待.今天,我们先来复习一下2014年发布的Java 8的十大新特性. Java 8可谓是自Java 5以来最具革命性的版本了 ...

  8. 关于cc -o命令

    这个命令很灵活,格式是: cc -o 目标二进制可执行文件 文件1 文件2 文件3 ..... 其中目标文件后面的文件,可为源代码,也可为二进制文件,也可为库文件 比如: //a.c #include ...

  9. mysql 查询优化 ~explain解读之extra解读

    一 explain 常用状态 1 using filesort 常见于order by 字段 无法走索引造成,文件排序.需要注意优化,复杂条件可以选择建立联合索引进行优化2 using join bu ...

  10. Java编程:悲观锁、乐观锁的区别及使用场景

    定义: 悲观锁(Pessimistic Lock): 每次获取数据的时候,都会担心数据被修改,所以每次获取数据的时候都会进行加锁,确保在自己使用的过程中数据不会被别人修改,使用完成后进行数据解锁.由于 ...