容器接口

BeanFactory

  • 是ApplicationContext的父接口,所有ApplicationContext的实现都组合了BeanFactory。

  • BeanFactory才是Spring的核心容器。

从BeanFactory提供的方法来看,主要是从容器中获取Bean。实际上控制反转,依赖注入以及Bean的生命周期管理,都由它的实现类提供。如下展示了BeanFactory其中一个实现类DefaultListableBeanFactory的继承关系。

可以看到,它的继承路线上有一个DefaultSingletonBeanRegistry类,这个类我们打开可以看到如下代码段,其中singletonObjects对象正是容器中所有单例对象被保存的地方。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 保存了所有的单例对象 /** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); ...
}

ApplicationContext

ApplicationContext继承自多个接口,因此提供了多种能力,具体提供的能力如下代码所示。

@SpringBootApplication
public class SsmpApplication { public static void main(String[] args) throws IOException {
final ConfigurableApplicationContext context = SpringApplication.run(SsmpApplication.class, args); // MessageSource接口提供的功能,实现国际化能力
context.getMessage("hi", null, Locale.CHINA);
context.getMessage("hi", null, Locale.US); // ResourcePatternResolver接口提供的能力,实现读取资源文件的能力
final Resource[] resources = context.getResources("classpath*:spring.factories"); // EnvironmentCapable接口提供的能力,实现获取环境参数的能力,可以获取环境变量、配置等
final String java_home = context.getEnvironment().getProperty("java_home");
final String port = context.getEnvironment().getProperty("server.port"); // ApplicationEventPublisher提供的能力,可以发送事件,实现解耦
context.publishEvent(new MyEvent(context));
} public static class MyEvent extends ApplicationEvent { public MyEvent(Object source) {
super(source);
}
}
}

容器实现

BeanFactory实现

以下代码的注释中展示了BeanFactory是如何注册Bean的,以及注册后如何进行后处理的。

点击查看代码
package com.leo.ssmp;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.Collection; @SpringBootApplication
@Slf4j
public class SsmpApplication { public static void main(String[] args) {
// 将MyConfig类注册到BeanFactory中,由BeanFactory管理Bean的生成,销毁
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
final BeanDefinition configDefinition = BeanDefinitionBuilder.genericBeanDefinition(MyConfig.class)
.setScope("singleton")
.getBeanDefinition();
beanFactory.registerBeanDefinition("config", configDefinition); // 向BeanFactory上注册一些后处理器,这些后处理器可以解析@Configuration和@Bean这些注解
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); // BeanFactory后处理器,执行后处理操作,处理@Configuration注解,将bean1和bean2生成出来
final Collection<BeanFactoryPostProcessor> beanFactoryPostProcessors = beanFactory.getBeansOfType(
BeanFactoryPostProcessor.class).values();
log.info("---------------BeanFactory后处理器------------------");
beanFactoryPostProcessors.forEach(beanFactoryPostProcessor -> log.info(beanFactoryPostProcessor.toString()));
beanFactoryPostProcessors.forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
log.info("---------------BeanFactory后处理器------------------"); // Bean后处理器,针对Bean的生命周期的各个阶段做扩展,例如@Autowired @Resource,
// 这样才能在生成bean1后,向bean1中注入bean2
final Collection<BeanPostProcessor> beanPostProcessors = beanFactory.getBeansOfType(BeanPostProcessor.class)
.values();
log.info("----------------Bean后处理器-----------------");
beanPostProcessors.forEach(beanPostProcessor -> log.info(beanPostProcessor.toString()));
beanPostProcessors.forEach(beanFactory::addBeanPostProcessor);
log.info("----------------Bean后处理器-----------------"); log.info("------------------注册的所有Bean定义信息------------------");
final String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
log.info(beanDefinitionName);
}
log.info("------------------注册的所有Bean定义信息------------------"); final Bean1 bean1 = beanFactory.getBean(Bean1.class);
log.info(bean1.getBean2().toString());
} @Configuration
static class MyConfig {
@Bean
public Bean1 bean1() {
return new Bean1();
} @Bean
public Bean2 bean2() {
return new Bean2();
}
} static class Bean1 { @Autowired
private Bean2 bean2; public Bean1() {
log.info("Bean1 construct...");
} public Bean2 getBean2() {
return bean2;
}
} static class Bean2 {
public Bean2() {
log.info("Bean2 construct");
}
}
}

以上代码的运行结果如下:

点击查看代码
10:56:43.379 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
10:56:43.395 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
10:56:43.398 [main] INFO com.leo.ssmp.SsmpApplication - ---------------BeanFactory后处理器------------------
10:56:43.398 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.ConfigurationClassPostProcessor@724af044
10:56:43.398 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.event.EventListenerMethodProcessor@4678c730
10:56:43.512 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
10:56:43.513 [main] INFO com.leo.ssmp.SsmpApplication - ---------------BeanFactory后处理器------------------
10:56:43.513 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
10:56:43.513 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
10:56:43.516 [main] INFO com.leo.ssmp.SsmpApplication - ----------------Bean后处理器-----------------
10:56:43.516 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6385cb26
10:56:43.516 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@38364841
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - ----------------Bean后处理器-----------------
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - ------------------注册的所有Bean定义信息------------------
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - config
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.internalConfigurationAnnotationProcessor
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.internalAutowiredAnnotationProcessor
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.annotation.internalCommonAnnotationProcessor
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.event.internalEventListenerProcessor
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - org.springframework.context.event.internalEventListenerFactory
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - bean1
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - bean2
10:56:43.517 [main] INFO com.leo.ssmp.SsmpApplication - ------------------注册的所有Bean定义信息------------------
10:56:43.517 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
10:56:43.518 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
10:56:43.529 [main] INFO com.leo.ssmp.SsmpApplication - Bean1 construct...
10:56:43.535 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
10:56:43.536 [main] INFO com.leo.ssmp.SsmpApplication - Bean2 construct
10:56:43.537 [main] INFO com.leo.ssmp.SsmpApplication - com.leo.ssmp.SsmpApplication$Bean2@55040f2f Process finished with exit code 0

后处理器的执行顺序跟它们之间的排序策略有关,先执行的后处理器会生效。

ApplicationContext实现

ClassPathXmlApplicationContext

首先我们定义一个实体类

package com.leo.domain;

import lombok.Data;

@Data
public class Book {
private Integer id; private String type; private String name; private String description;
}

resources目录下创建b01.xml文件作为Spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="bean1" class="com.leo.domain.Book"/>
</beans>

通常我们会使用如下方式来启动和加载Spring容器

package com.leo;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource; @SpringBootApplication
public class SpringApplication {
public static void main(String[] args) {
final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"b01.xml");
}
}

其内部实现如果简单的拆开来,可以用如下步骤表示,BeanFactory是真正的容器,我们使用XmlBeanDefinitionReader将xml中定义的bean转化成BeanDefinition并注册到BeanFactory中。

package com.leo;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource; @SpringBootApplication
public class SpringApplication {
public static void main(String[] args) {
testClasspathXmlApplicationContext();
} private static void testClasspathXmlApplicationContext() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("=======================>before");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
System.out.println("=======================>after");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}

以上代码的运行结果如下:

=======================>before
14:14:13.483 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 6 bean definitions from class path resource [b01.xml]
=======================>after
bean1

我们会发现这是容器里只有一个Bean,但是当我们用springboot自动配置来启动容器时,会发现即使我们不定义Bean,默认也会加载一些内置的bean。那么Spring是如何加载这些内置的Bean的呢。我们可以在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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="bean1" class="com.leo.ssmp.domain.Book"/> <!--这里开启了各种注解,例如Autowired-->
<context:annotation-config/>
</beans>

这样我们运行上面的代码时打印出来的结果如下:

=======================>before
14:14:13.483 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 6 bean definitions from class path resource [b01.xml]
=======================>after
bean1
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

可以看到这时已经加载了很多处理注解和事件监听的Bean。

FileSystemXmlApplicationContext

基本原理与ClassPathXmlApplicationContext相似,只不过这里改为从文件系统直接读取xml配置。

AnnotationConfigApplicationContext

直接通过@Configuration注解的类来加载Bean,这种方法加载Bean时,会默认加载注解处理器这些内置的Bean。同时还会将config类也加载为Bean。

Spring原理(1)——容器的更多相关文章

  1. Spring MVC 原理探秘 - 容器的创建过程

    1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...

  2. spring 原理1:java 模拟springIOC容器

    本篇博客主要是使用java代码模拟spring的IOC容器,实现依赖注入:当然只是模拟spring容器中简单的一点实现原理而已,加深一些自己对spring框架的底层原理的理解: 使用的技术:dom4j ...

  3. Spring框架IOC容器和AOP解析

    主要分析点: 一.Spring开源框架的简介  二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面向切面编程(AOP)和事务管理配置  一.S ...

  4. 03 Spring的父子容器

    1.概念理解和知识铺垫 在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的,而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,而且容器有上下层关 ...

  5. spring 原理

    1.spring原理 内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建.调用对象,Spring就是在运 ...

  6. 学习认识Spring原理

    学习认识Spring原理 Spring 是一种业务层框架.搭建Spring框架需要Spring开发包和commons-logging包.Spring的核心思想是控制反转也称依赖注入(创建者--(实例) ...

  7. Spring框架IOC容器和AOP解析 非常 有用

    Spring框架IOC容器和AOP解析   主要分析点: 一.Spring开源框架的简介  二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面 ...

  8. 7.1 Spring原理

    7.1 Spring原理 一.spring是什么?(IOC.AOP.MVC) Spring是一个基于IOC和AOP的结构J2EE系统的框架 , 1.1 IOC 控制反转 是Spring的基础,Inve ...

  9. Spring——原理解析-利用反射和注解模拟IoC的自动装配

    解析Spring的IoC容器基于注解实现的自动装配(自动注入依赖)的原理 1.本文案例 使用注解和反射机制来模拟Spring中IoC的自动装配功能 定义两个注解:@Component,用来标注组件:@ ...

  10. Spring原理系列一:Spring Bean的生命周期

    一.前言 在日常开发中,spring极大地简化了我们日常的开发工作.spring为我们管理好bean, 我们拿来就用.但是我们不应该只停留在使用层面,深究spring内部的原理,才能在使用时融汇贯通. ...

随机推荐

  1. egret 图片跨域

    //图片跨域 egret.ImageLoader.crossOrigin = "anonymous";

  2. k8s容器互联-flannel host-gw原理篇

    k8s容器互联-flannel host-gw原理篇 容器系列文章 容器系列视频 简析host-gw 前面分析了flannel vxlan模式进行容器跨主机通信的原理,但是vxlan模式需要对数据包进 ...

  3. Zookeeper 从入门到精通

    更多内容,前往IT-BLOG 一.Zookeeper概述 Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目.Zookeeper从设计模式角度来理解:是一个基于观察者模 ...

  4. dark room - 2020 年苹果设计奖得主,一个足够强大的照片视频编辑器

    2020年苹果设计奖得主 2015年App Store最佳应用 Darkroom 是一个高级照片和视频编辑器.它对业余摄影师来说很容易操作,但对专业摄影师来说足够强大. 下载 ➤ Darkroom 下 ...

  5. C#中抽象方法与虚方法的区别详解及示例

    1. 抽象方法与虚方法的区别   先说两者最大的区别:抽象方法是需要子类去实现的.虚方法是已经实现了的,可以被子类覆盖,也可以不覆盖,取决于需求.因为抽象类无法实例化,所以抽象方法没有办法被调用,也就 ...

  6. ES6中的解构赋值(数组,对象,嵌套,默认值)

    解构赋值 通过解构赋值,可以快速从对象或者数组中取出属性或者数值. 解构赋值 可以通过定位到数组或者对象的某一个位置,将值直接赋给一个或多个变量. const arr = ['dasha', 'ers ...

  7. Python中,类的特殊方法与内置函数的关联

    目录 Python类 Python类的设计原则 特殊方法[Special methods] Duck typing 内置函数 English Version The key design princi ...

  8. python医学病理图片svs装换

    SVS文件是什么? 最开始拿到SVS文件一脸懵逼的,这货长这样(在windows下可以用Aperio ImageScope这个开源软件打开): 我现在接触的这种图片的大小一般在60M-1.5G之间,可 ...

  9. [Web Server]Tomcat调优之工作原理、线程池/连接池

    1 Tomcat 概述 Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛. 1.0 Tomcat 容器与原理 1.0.1 Tomcat组件构成 注意,如图所示,阴影部 ...

  10. 600 条最强 Linux 命令总结

    600 条最强 Linux 命令总结 每博一文案 你有千万条微博想写,可有些根本不重要,后来你才懂那是你怕别人看穿你所以才把真话埋在日常里.你有千万句话想说,可点开那 个对话框,你根本打不出一个字.你 ...