1.基础知识

Spring有两个核心功能,分别是ioc和aop,其中ioc是控制反转,aop是切面编程。

在ioc中,还有一个名次叫DI,也就是依赖注入。嗯,好像IOC和DI是指同一个,好像又感觉他俩不是同一个。

具体的区别是:IOC是DI的原理。依赖注入是向某个类或方法注入一个值,其中所用到的原理就是控制反转。

所以说到操作层面的时候用DI,原理层的是说IOC,下文亦同。

对于DI最新使用方法,一般都是Java注解去标识。但是用这种方式去看源码,好像不太适合。用XML的方式,根据一个demo来进行源码的阅读,比较适合。

2.demo代码

BeanService:

public interface BeanService {
String getName();
}

BeanServiceImpl:

public class BeanServiceImpl implements BeanService {
public String getName() {
return "----------------------------------------:I am Bean";
}
}

applicationContext.xml:

<?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.xsd <!--ioc源码-->
<bean id="beanService" class="com.example.demo.ershi.IocSource.BeanServiceImpl"/> </beans>

test代码:

public class BeanTest {
public static void main(String[] args) {
// 加载xml配置
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContextF.xml"); // IOC获取Bean
BeanService beanService = context.getBean(BeanService.class); System.out.println(beanService.getName());
}
}

测试结果:

22:01:07.069 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanService'
22:01:07.069 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'beanService'
22:01:07.069 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Eagerly caching bean 'beanService' to allow for resolving potential circular references
22:01:07.069 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'beanService'
22:01:07.070 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@67205a84]
22:01:07.070 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
22:01:07.071 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
22:01:07.072 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'beanService'
----------------------------------------:I am Bean

3.源码阅读

3.1 Bean的含义

前置先解释下这个Bean的含义,因为会贯穿整个流程。
通俗地讲,Bean就是IOC的容器。如上面的例子,将BeanService注册到Spring里,那么BeanService就是Spring的里面的一个Bean。Demo里面context.getName()就是从Spring中取出这个Bean,完成控制反转的。
所以我们的重点就是要看看Spring到底是怎么生成管理这些Bean的。

3.2 ClassPathXmlApplicationContext

启动类中,加载配置的ClassPathXmlApplicationContext肯定就是完成IOC的核心。不知道它到底是怎么做的,怎么入手呢?
先来看看它的类
先分析下这个类图:

  1. ClassPathXmlApplicationContext类是AbstractApplicationContext抽象类的子类
  2. AbstractApplicationContext类是ApplicaionContext接口的实现。
  3. ApplicaionContext接口集合了非常多的内容,其中和IOC比较相关的就是ListableBeanFactory接口和HierarchicalBeanFactory接口
  4. ListableBeanFactory接口和HierarchicalBeanFactory接口是继承BeanFactory

从此分析可以看出,ClassPathXmlApplicationContext是什么,了解下ApplicaionContext;它怎么和IOC有关,要了解BeanFactory
所以后面我们先来看看ApplicaionContextBeanFactory

3.3 ApplicationContext

/**
*提供应用程序配置的中央接口
*当应用程序运行时,这是只读的,但如果实现支持,则可以重新加载
*用于访问应用程序组件的Bean工厂方法
*以通用方式加载文件资源的能力
*拥有向注册侦听器发布事件的能力
*解析消息的能力,支持国际化
*为了让BeanFactory拥有生命周期,实现了一些类
*/
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver { /**
* 返回application context唯一的id
String getId(); /**
*返回上下文中已经部署的应用程序的名称
*/
String getApplicationName(); /**
* 返回一个展示名称
*/
String getDisplayName(); /**
* 程序第一次加载时返回时间.
*/
long getStartupDate(); /**
* 返回父应用程序
*/
ApplicationContext getParent(); /**
* Expose AutowireCapableBeanFactory functionality for this context.
*/
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }

ApplicationContext

从该接口的注解描述可知,ApplicationContext是整个项目的配置,Spring项目在启动或运行的时候都需要依赖到它。

其中Bean管理相关的则是ListableBeanFactoryHierarchicalBeanFactory

3.4 BeanFactory

ListableBeanFactoryHierarchicalBeanFactory都是继承BeanFactory的。

/**
*用于访问SpringBean容器的顶级接口
*根据bean的定义,工厂将返回包含对象的独立实例或者单例的对象
*HierarchicalBeanFactory是一个分层的Bean,如果实现了这个接口,所有方法都会经过父类的工厂。
* ListableBeanFactory这个接口是要实现预先加载Bean的配置,生成好实例,直接管理Bean的实例,而不是来一个请求,生成一个。
*/
public interface BeanFactory { /**
* 用来获得实例的引用,并且区分FactoryBean区分。
* 如果使用bean的名字myJndiObject获取FactoryBean,返回的是一个工厂,而不是工厂的实例;如果需要获得工厂实例,需要转义。
*/
String FACTORY_BEAN_PREFIX = "&"; /**
* 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.
*/
Object getBean(String name) throws BeansException; /**
* 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.并且增加了一个类型的检验。
*/
<T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; /**
* 根据给定类型返回匹配的bean实例.
*/
<T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; /**
* 检查spring的bean容器中是否包含有该bean
*/
boolean containsBean(String name); /**
* 判断bean的作用域是否是singleton
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /**
* 判断bena的作用域是否是prototype
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; /**
* 检查给定名称的bean是否和指定类型匹配.更确却的说是通过检查给定的bean,返回指定类型的目标对象
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; /**
* 获取给定名称的bean的class类型
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException; /**
* 获取给定bean名称的别名,如果根据别名检索,将会获得原始bean名称。
*
String[] getAliases(String name); } BeanFactory

BeanFactory

3.5初始化IOC容器

ClassPathXmlApplicationContext的构造函数看,最核心的就是refresh()函数,其他只是设一些值。
而这个refresh()是调用父类AbstractApplicationContext中的refresh()
根据它的注解可知它是加载刷新了整个context,并且加载所有Bean定义和创建对应的单例。

ClassPathXmlApplicationContext中refresh()方法:

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException { super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

AbstractApplicationContext中refresh()方法:

public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
//启动监控标识,并且同步此对象,防止同一时间有多个
//线程加载
synchronized(this.startupShutdownMonitor) {
//初始化一些上下文参数
this.prepareRefresh();
//创建一个BeanFactory,进去后只有两个方法this.refreshBeanFactory();
//return this.getBeanFactory();
//具体的实现在它的父类AbstractRefreshableApplicationContext中 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//为 此beanFactory初始化一些组件,比如:ClassLoadder等等
this.prepareBeanFactory(beanFactory); try {
//获取容器级别的后处理器,允许上下文的子类中对
//beanFactory进行后处理,在应用上下文内部beanFactory
//初始化之后可以修改beanFactory,此时所有的BeanDefinittions都
//已经被加载,但未被实例化,具体的实现在AbstractRefreshableWebApplicationContext
this.postProcessBeanFactory(beanFactory);
/**在装配完成配置后执行这些后处理器,这里涉及到一些接口
我们在开发时可以实现这些接口扩展功能,例如:
InstantiationAwareBeanPostProcessor包含两个方法
一个是在实例化前调用,一个在实例化后,初始化前调用
可以用来做特殊作用,例如代理等等
DestructionAwareBeanPostProcessor在销毁前调用
*/
this.invokeBeanFactoryPostProcessors(beanFactory);
/**
把所有的bean的后处理器排序,在bean实例化后调用
*/
this.registerBeanPostProcessors(beanFactory);
//初始化国际化信息资源
this.initMessageSource();
//初始化事件多播组件,Event触发时由Multicaster
//通知ApplicationListener
this.initApplicationEventMulticaster();
//空方法由子类扩展,可以在实例化bean之前
//做一些ApplicationContext相关的操作
this.onRefresh();
//注册事件监听器
this.registerListeners();
//单例模式的bean实例 化,初始化等等完成
this.finishBeanFactoryInitialization(beanFactory);
//applicationContext刷新完成后的处理,
//例如生命周期监听器的回调,广播通知等
this.finishRefresh();
} catch (BeansException var9) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
//如果加载失败,则清理环境相关的信息
this.destroyBeans();
//把applicationContext的active设置成false
this.cancelRefresh(var9);
throw var9;
} finally {
//清理一些缓存
this.resetCommonCaches();
} }
}

refresh()

里面有许多步骤,重点看下obtainFreshBeanFactory()(重新获取一个BeanFactory)。

它里面有个核心的方法refreshBeanFactory()

obtainFreshBeanFactory:

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

obtainFreshBeanFactory

AbstractRefreshableApplicationContext.refreshBeanFactory():
    @Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
//如果存在就销毁重建
destroyBeans();
closeBeanFactory();
}
try { //创建一个DefaultListableBeanFactory作为Bean的
//管理工厂类
DefaultListableBeanFactory beanFactory = createBeanFactory();
//加载自定义的beanFactory
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory); //加载beanDefinition,关系这个类加载的东西比较多
//可以单分析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

refreshBeanFactory

如果已有BeanFactory,先删除所有Bean,然后关闭BeanFactory。
然后创建一个新的ListableBeanFactory,上面说到这个工厂里会预先加载所有的Bean。
最后核心的就是loadBeanDefinitions(beanFactory),它是加载Bean的定义。实现交给了子类。

AbstractXmlApplicationContext.loadBeanDefinitions方法:

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
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);
}
}

loadBeanDefinitions

用的是XmlBeanDefinitionReader直接读配置文件加载Bean Definition(Bean定义)到BeanFactory。它里面一步步把xml的配置文件拆解读取,把一个个Bean Definition加载到BeanFactory里。
至此,已经有用一个加载好Bean Definition的BeanFactory了。

3.6 依赖注入

回到启动类中,看看怎么从context中获取bean的。

// IOC获取Bean
BeanService beanService = context.getBean(BeanService.class);

是根据类去拿bean的,当然也可以根据id。

其对应的源码实现,在DefaultListableBeanFactory中,上文有说到对应的BeanFactory选型。

是根据类去拿bean的,当然也可以根据id。
其对应的源码实现,在DefaultListableBeanFactory中,上文有说到对应的BeanFactory选型。

DefaultListableBeanFactory.getBean()

    @Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
BeanFactory parent = getParentBeanFactory();
if (parent != null) {
return parent.getBean(requiredType, args);
}
throw new NoSuchBeanDefinitionException(requiredType);
}

getBean

NamedBeanHolder是里面包含一个实例化的对象,和bean的名字。resolveNamedBean()是怎么拿出Bean的关键。
一步步Debug,可以看到,它是遍历BeanFactory里面维护的beanDefinitionNames和manualSingletonNames成员变量,找出命中的beanName返回。

resolveNamedBean(requiredType,args)➡️getBeanNamesForType(requiredType)➡️getBeanNamesForType(type,true,true)➡️doGetBeanNamesForType(ResolvableType.forRawClass(type),includeNonSingletons, allowEagerInit)

DefaultListableBeanFactory.doGetBeanNamesForType():

    private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<String>(); // Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name
// is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// In case of FactoryBean, match object created by FactoryBean.
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound =
(allowEagerInit || !isFactoryBean ||
(dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
(includeNonSingletons ||
(dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
isTypeMatch(beanName, type);
if (!matchFound && isFactoryBean) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably contains a placeholder: let's ignore it for type matching purposes.
if (this.logger.isDebugEnabled()) {
this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex);
}
onSuppressedException(ex);
}
catch (BeanDefinitionStoreException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably contains a placeholder: let's ignore it for type matching purposes.
if (this.logger.isDebugEnabled()) {
this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex);
}
onSuppressedException(ex);
}
}
} // Check manually registered singletons too.
for (String beanName : this.manualSingletonNames) {
try {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
if (logger.isDebugEnabled()) {
logger.debug("Failed to check manually registered singleton with name '" + beanName + "'", ex);
}
}
} return StringUtils.toStringArray(result);
}

doGetBeanNamesForType

然后拿着这个beanName去找具体的bean实例。这里的代码比较长,在AbstractBeanFactory里面的doGetBean()中实现。
大意是先尝试去找手动添加bean的单例工厂里找有没有对应的实例,没有的话就往父类beanFactory里面找,最后没有的话就生成一个。
spring中一个bean是如何加载和如何注入大致如此。

参考:零基础带你看Spring源码——IOC控制反转

参考:Spring bean的生命周期

最新文章

  1. .Net Core Linux centos7行—.net core json 配置文件
  2. jquery相关校验以及jquery其他知识总结
  3. [转] React Router 使用教程
  4. webservice asmx 无法序列化接口 System.Collections.Generic.IList
  5. 冒泡排序----java实现
  6. SharePoint RBS 安装(集成Office Web Apps)
  7. WiresShark 一站式学习
  8. 分而治之(Work Breakdown Structure, WBS)
  9. MVVM探索:从ViewModel关闭Window的最佳实践
  10. 【移动端】移动端字体单位font-size选择px还是rem
  11. Hanlp中N最短路径分词详细介绍
  12. 学习Spring Boot:(二十二)使用 AOP
  13. UVALive - 7637 E - Balanced String(构造)
  14. asp.net要验证的用户名和密码
  15. Windows和Linux双系统下完美卸载linux
  16. 如何将pip更新到最新版
  17. 极光客户互动云java post请求
  18. CentOS 中安装 mysql 5.7+
  19. tomcat使用不同的jdk版本 liunx 装两个jdk
  20. bzoj4897 [Thu Summer Camp2016]成绩单

热门文章

  1. mysql中的正则操作 匹配手机号,匹配中文,替换
  2. Learning to Track Any Object
  3. git 执行 git reset HEAD 报 Unstaged changes after reset
  4. 使用CompletableFuture实现业务服务的异步调用实战代码
  5. phpspreadsheet
  6. BIO,NIO,AIO到NETTY
  7. layui 复选框checkbox 实现全选全选
  8. Docker网络模式介绍
  9. 【451】python 同一行打印进度条
  10. Idea导入maven项目没有识别