感谢黑马满老师的讲解,通俗易懂,很适合去学习。
视频地址:Spring高级49讲-导学_哔哩哔哩_bilibili
学习目标:
通过这个示例结合 debug 查看 ApplicationContext 对象的内部结构
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- context.getBean("aaa");
- System.out.println(context);
- }
- }
BeanFactory 接口典型功能:getBean方法
- //AbstractApplicationContext类
- public Object getBean(String name) throws BeansException {
- this.assertBeanFactoryActive();
- //内部调用了beanFactory的getBean方法
- return this.getBeanFactory().getBean(name);
- }
debug查看context内部结构

ConfigurableApplicationContext继承关系:

总结:到底什么是 BeanFactory
它是 ApplicationContext 的父接口
它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory
BeanFactory接口:
- public interface BeanFactory {
- String FACTORY_BEAN_PREFIX = "&";
-
- Object getBean(String var1) throws BeansException;
-
-
T getBean(String var1, Class var2) throws BeansException; -
- Object getBean(String var1, Object... var2) throws BeansException;
-
-
T getBean(Class var1) throws BeansException; -
-
T getBean(Class var1, Object... var2) throws BeansException; -
-
ObjectProvider getBeanProvider(Class var1) ; -
-
ObjectProvider getBeanProvider(ResolvableType var1); -
- 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;
-
- @Nullable
- Class> getType(String var1) throws NoSuchBeanDefinitionException;
-
- @Nullable
- Class> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
-
- String[] getAliases(String var1);
- }
表面上只有 getBean,实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供。
查看它的实现类

我们知道BeanFactory能管理所有的bean,最为熟悉的就是单例bean,其中DefaultSingletonBeanRegistry就管理了所有的单例对象。
通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
- singletonObjects.setAccessible(true);
- //获取beanFactory
- ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
- //获取beanFactory对象的singletonObjects属性
- Map
map = (Map) singletonObjects.get(beanFactory); - //由于对象太多,我们只打印名称以component开头的对象
- map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
- .forEach( e -> {
- System.out.println(e.getKey() + "=" + e.getValue());
- });
- }
- }
- @Component
- public class Component1 {
-
- }
-
- @Component
- public class Component2 {
-
- }
结果:
- component1=com.itheima.a01.Component1@16eedaa6
- component2=com.itheima.a01.Component2@28501a4b

查看类图,可以发现ApplicationContext多实现了四个接口,也就可以回答下面的问题了。
ApplicationContext 比 BeanFactory 多点啥:
ApplicationContext 组合并扩展了 BeanFactory 的功能
国际化、通配符方式获取一组 Resource 资源、整合 Environment 环境、事件发布与监听
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- System.out.println(context.getMessage("hi", null, Locale.CHINA));
- System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
- System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
- }
国际化文件均在 src/resources 目录下
messages.properties(空),空的 messages.properties 也必须存在。
messages_en.properties
hi=Hello
messages_ja.properties
hi=こんにちは
messages_zh.propertieshi=你好
hi=你好
结果:
- 你好
- Hello
- こんにちは
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- //Resource[] resources = context.getResources("classpath:application.properties");
-
- //classpath:META-INF/spring.factories:在类路径找,如果在jar包中是找不到的
- //classpath*:META-INF/spring.factories:这样就可以
- Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
- for (Resource resource : resources) {
- System.out.println(resource);
- }
- }
结果:第一个是自己模块的,剩下的是导入的jar中的
- URL [file:/E:/spring%e6%ba%90%e7%a0%81/%e4%bb%a3%e7%a0%81/show/target/classes/META-INF/spring.factories]
- URL [jar:file:/D:/developer_tools/maven/repository/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]
- URL [jar:file:/D:/developer_tools/maven/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]
- URL [jar:file:/D:/developer_tools/maven/repository/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]
- URL [jar:file:/D:/developer_tools/maven/repository/org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.2.0/mybatis-spring-boot-autoconfigure-2.2.0.jar!/META-INF/spring.factories]
- URL [jar:file:/D:/developer_tools/maven/repository/com/alibaba/druid-spring-boot-starter/1.2.8/druid-spring-boot-starter-1.2.8.jar!/META-INF/spring.factories]
- URL [jar:file:/D:/developer_tools/maven/repository/org/springframework/spring-test/5.3.10/spring-test-5.3.10.jar!/META-INF/spring.factories]
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- //不区分大小写
- System.out.println(context.getEnvironment().getProperty("java_home"));
- System.out.println(context.getEnvironment().getProperty("server.port"));
- }
结果:
- D:\developer_tools\jdk\1.8.0_131
- 8082
Spring中任何一个组件都可以作为监听器,这里用Component2
事件类
- public class UserRegisteredEvent extends ApplicationEvent {
- public UserRegisteredEvent(Object source) {
- super(source);
- }
- }
发送事件
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- //发送事件
- context.publishEvent(new UserRegisteredEvent(context));
- }
监听器
- @Component
- public class Component2 {
-
- private static final Logger log = LoggerFactory.getLogger(Component2.class);
-
- //监听器,方法名任意,参数要求:与发送的事件类型一致
- @EventListener
- public void aaa(UserRegisteredEvent event) {
- log.debug("{}", event);
- }
- }
结果
- [DEBUG] 10:00:42.236 [main] com.itheima.a01.Component2
- -com.itheima.a01.UserRegisteredEvent
- [source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@747edf66,
- started on Tue Nov 01 10:00:39 CST 2022]
完成用户注册与发送短信之间的解耦
发送事件
- @Component
- public class Component1 {
-
- private static final Logger log = LoggerFactory.getLogger(Component1.class);
-
- //具备发送事件的功能
- @Autowired
- private ApplicationEventPublisher context;
-
- public void register() {
- log.debug("用户注册");
- //发布事件
- context.publishEvent(new UserRegisteredEvent(this));
- }
-
- }
监听事件
- @Component
- public class Component2 {
-
- private static final Logger log = LoggerFactory.getLogger(Component2.class);
-
- //监听器,方法名任意,参数要求:与发送的事件类型一致
- @EventListener
- public void aaa(UserRegisteredEvent event) {
- log.debug("{}", event);
- log.debug("发送短信");
- }
- }
从容器获取Component1调用其方法
- @SpringBootApplication
- public class A01 {
-
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
-
- ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
-
- context.getBean(Component1.class).register();
- }
学习目标:
Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考
DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转和依赖注入功能,都是它来实现
ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)
FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)
XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)
AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)
AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)
AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)
AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器(新)
另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来
原始的DefaultListableBeanFactory
- public class TestBeanFactory {
-
- public static void main(String[] args) {
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
-
- //bean的定义(class,scope,初始化,销毁)
- AbstractBeanDefinition beanDefinition
- = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
- //注册beandefinition对象
- //参数一:名字 ,参数二:具体bean
- beanFactory.registerBeanDefinition("config", beanDefinition);
-
- //输出容器中bean的名字
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- }
-
- @Configuration
- static class Config {
- @Bean
- public Bean1 bean1(){
- return new Bean1();
- }
-
- @Bean
- public Bean2 bean2(){
- return new Bean2();
- }
- }
-
- static class Bean1 {
- private static final Logger log = LoggerFactory.getLogger(Bean1.class);
-
- public Bean1() {
- log.debug("构造 Bean1()");
- }
-
- @Autowired
- private Bean2 bean2;
-
- public Bean2 getBean2() {
- return bean2;
- }
- }
-
- static class Bean2 {
- private static final Logger log = LoggerFactory.getLogger(Bean2.class);
-
- public Bean2() {
- log.debug("构造 Bean2()");
- }
- }
-
- }
结果:容器中只有一个config对象,原始的beanFactory并没有解析注解的能力
config
1)给BeanFactory添加一些常用的后处理器
- public class TestBeanFactory {
-
- public static void main(String[] args) {
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
-
- //bean的定义(class,scope,初始化,销毁)
- AbstractBeanDefinition beanDefinition
- = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
- //注册beandefinition对象
- //参数一:名字 ,参数二:具体bean
- beanFactory.registerBeanDefinition("config", beanDefinition);
-
- //给BeanFactory添加一些常用的后处理器,仅仅是注册后处理器
- AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
-
- //输出容器中bean的名字
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- }
- }
结果:仅仅是注册了后处理器,还没有执行,此时并不具备解析注解的能力
- config
- 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
2)执行BeanFactory后置处理器
- public class TestBeanFactory {
-
- public static void main(String[] args) {
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
-
- //bean的定义(class,scope,初始化,销毁)
- AbstractBeanDefinition beanDefinition
- = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
- //注册beandefinition对象
- //参数一:名字 ,参数二:具体bean
- beanFactory.registerBeanDefinition("config", beanDefinition);
-
- //给BeanFactory添加一些常用的后处理器,仅仅是注册后处理器
- AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
-
- //执行BeanFactory后置处理器
- beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
- .stream().forEach(beanFactoryPostProcessor -> {
- beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
- });
-
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- System.out.println(beanFactory.getBean(Bean1.class).getBean2());
-
- }
- }
结果: bean1,bean2成功注册进容器,但是bean1获取不到bean2对象,结果为null。
并且可以发现是懒加载,第一次用到的时候才创建对象实例
- config
- 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
- bean1
- bean2
- [DEBUG] 15:34:11.550 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1()
- null
原因:输出刚才执行的后处理器,发现没有执行@Autowire后处理器
- System.out.println(beanFactory.getBean(Bean1.class).getBean2());
-
- [org.springframework.context.annotation.ConfigurationClassPostProcessor@24313fcc,
- org.springframework.context.event.EventListenerMethodProcessor@7d20d0b]
3)执行Bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowire,@Resource
- public class TestBeanFactory {
-
- public static void main(String[] args) {
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
-
- //bean的定义(class,scope,初始化,销毁)
- AbstractBeanDefinition beanDefinition
- = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
- //注册beandefinition对象
- //参数一:名字 ,参数二:具体bean
- beanFactory.registerBeanDefinition("config", beanDefinition);
-
- //给BeanFactory添加一些常用的后处理器,仅仅是注册后处理器
- AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
-
- //执行BeanFactory后置处理器
- beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
- .stream().forEach(beanFactoryPostProcessor -> {
- beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
- });
-
- //执行Bean后处理器
- beanFactory.getBeansOfType(BeanPostProcessor.class).values()
- .forEach(beanPostProcessor -> {
- //查看Bean后处理器顺序
- System.out.println(">>>>" + beanPostProcessor);
- //添加Bean后处理器
- beanFactory.addBeanPostProcessor(beanPostProcessor);
- });
-
- System.out.println(beanFactory.getBean(Bean1.class).getBean2());
-
- }
- }
结果:
- >>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@76908cc0
- >>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@2473d930
- [DEBUG] 15:50:59.132 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1()
- [DEBUG] 15:50:59.149 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2()
- com.itheima.a02.TestBeanFactory$Bean2@188715b5
我们可以在获取bean前调用下面的方法准备好单例,就不用到使用时才去创建实例。
- beanFactory.preInstantiateSingletons(); //准备好所有单例
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>");//为了区分是在获取前创建的
结果:
- >>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@76908cc0
- >>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@2473d930
- [DEBUG] 15:56:20.124 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1()
- [DEBUG] 15:56:20.138 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2()
- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- com.itheima.a02.TestBeanFactory$Bean2@43195e57
此时增加bean3,bean4
- @Configuration
- static class Config {
- @Bean
- public Bean1 bean1(){
- return new Bean1();
- }
-
- @Bean
- public Bean2 bean2(){
- return new Bean2();
- }
-
- @Bean
- public Bean3 bean3() {
- return new Bean3();
- }
-
- @Bean
- public Bean4 bean4() {
- return new Bean4();
- }
- }
-
-
- static class Bean1 {
- private static final Logger log = LoggerFactory.getLogger(Bean1.class);
-
- public Bean1() {
- log.debug("构造 Bean1()");
- }
-
- @Autowired
- private Bean2 bean2;
-
- public Bean2 getBean2() {
- return bean2;
- }
-
- }
-
- static class Bean2 {
- private static final Logger log = LoggerFactory.getLogger(Bean2.class);
-
- public Bean2() {
- log.debug("构造 Bean2()");
- }
- }
-
- interface Inter {
-
- }
-
- static class Bean3 implements Inter {
-
- }
-
- static class Bean4 implements Inter {
-
- }
关于@Autowire的一些点,这里说明一下
我要在bean1里面这样注入,能成功吗?注入失败,容器中bean3,bean4都匹配
- @Autowired
- private Inter inter;
但是这样就可以,当有多个bean匹配时,通过名字进一步匹配
- @Autowired
- private Inter bean3
可以发现我刚刚打印了Bean后处理器的顺序,这个有什么用?看这个例子,请问注入的是bean3还是bean4呢
注入bean3,与后处理器顺序有关,先解析Autowire
- @Autowired
- @Resource(name = "bean4")
- private Inter bean3;
设置Bean后处理器顺序,通过优先级排序。
- //Bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowire,@Resource
- beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
- .sorted(beanFactory.getDependencyComparator()).
- forEach(beanPostProcessor -> {
- //添加Bean后处理器
- beanFactory.addBeanPostProcessor(beanPostProcessor);
- });
查看源码,它们都实现了 Ordered 接口,设置Ordered大小进行排序,ordered小的优先级高
- //AutowiredAnnotationBeanPostProcessor类
- private int order = 2147483645;
-
- //CommonAnnotationBeanPostProcessor类
- public CommonAnnotationBeanPostProcessor() {
- this.setOrder(2147483644);
- this.setInitAnnotationType(PostConstruct.class);
- this.setDestroyAnnotationType(PreDestroy.class);
- this.ignoreResourceType("javax.xml.ws.WebServiceContext");
- }
-
- public interface Ordered {
- int HIGHEST_PRECEDENCE = -2147483648;
- int LOWEST_PRECEDENCE = 2147483647;
-
- int getOrder();
- }
beanFactory.getDependencyComparator()是什么?

查看源码:可以发现
- public class AnnotationAwareOrderComparator extends OrderComparator {
- }
- public class OrderComparator implements Comparator
- public int compare(@Nullable Object o1, @Nullable Object o2) {
- return this.doCompare(o1, o2, (OrderComparator.OrderSourceProvider)null);
- }
-
- private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderComparator.OrderSourceProvider sourceProvider) {
- boolean p1 = o1 instanceof PriorityOrdered;
- boolean p2 = o2 instanceof PriorityOrdered;
- if (p1 && !p2) {
- return -1;
- } else if (p2 && !p1) {
- return 1;
- } else {
- int i1 = this.getOrder(o1, sourceProvider);
- int i2 = this.getOrder(o2, sourceProvider);
- return Integer.compare(i1, i2);
- }
- }
- }
beanFactory 不会做的事:
- 不会主动调用 BeanFactory 后处理器
- 不会主动添加 Bean 后处理器
- 不会主动初始化单例
- 不会解析beanFactory 还不会解析 ${ } 与 #{ }
bean 后处理器会有排序的逻辑
从类路径查找 XML 配置文件,创建容器
- public class A02Application {
- public static void main(String[] args) {
- testClassPathXmlApplicationContext();
- }
-
- // 较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
- private static void testClassPathXmlApplicationContext() {
- ClassPathXmlApplicationContext context =
- new ClassPathXmlApplicationContext("b01.xml");
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- System.out.println(context.getBean(Bean2.class).getBean1());
- }
-
-
- static class Bean1 {
- }
-
- static class Bean2 {
-
- private Bean1 bean1;
-
- public void setBean1(Bean1 bean1) {
- this.bean1 = bean1;
- }
-
- public Bean1 getBean1() {
- return bean1;
- }
- }
- }
b01.xml
- "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.itheima.a02.A02Application.Bean1"/>
-
-
- <bean id="bean2" class="com.itheima.a02.A02Application.Bean2">
-
- <property name="bean1" ref="bean1"/>
- bean>
- beans>
结果:
- bean1
- bean2
- com.itheima.a02.A02Application$Bean1@4b168fa9
我们在Spring基础中都学过这个标签,作用是让系统能够识别相应的注解
<context:annotation-config/>
现在我们看看到底是为什么呢?
加上这个标签,打印容器中的bean,发现多了几个后处理器,用来解析@Configuration,@Autowire,@Resourse等注解
- bean1
- bean2
- 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
基于磁盘路径下 xml 格式的配置文件来创建
- public class A02Application {
- public static void main(String[] args) {
- testFileSystemXmlApplicationContext();
- }
-
- private static void testFileSystemXmlApplicationContext() {
- FileSystemXmlApplicationContext context =
- new FileSystemXmlApplicationContext("src\\main\\resources\\b01.xml");
-
- //相对路径(模块开始):src\main\resources\b01.xml
- //绝对路径:E:\spring源码\代码\show\src\main\resources\b01.xml
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- System.out.println(context.getBean(Bean2.class).getBean1());
- }
- }
结果:
- bean1
- bean2
- com.itheima.a02.A02Application$Bean1@4b168fa9
测试的时候遇到了一个报错,如下
- Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException:
- IOException parsing XML document from file
- [D:\workspace_idea2\spring_yuanli\src\main\resources\b01.xml];
- nested exception is java.io.FileNotFoundException: src\main\resources\b01.xml
原因:这个项目是导进去的,与默认的工作目录不一样导致的。
处理方法:Edit Configurations -> 修改工作目录
原理:前面说过,ApplicationContext内部还是需要beanFactory的支持
比DefaultListableBeanFactory多的功能,加载bean的定义信息
- public class A02Application {
- public static void main(String[] args) {
-
- DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
- System.out.println("读取之前...");
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- System.out.println("读取之后...");
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
- reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
- //reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\b01.xml"));
- for (String name : beanFactory.getBeanDefinitionNames()) {
- System.out.println(name);
- }
- }
结果:
- 读取之前...
- 读取之后...
- bean1
- bean2
- 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
Spring boot 中非 web 环境容器,较为经典的容器, 基于 java 配置类来创建
- private static void testAnnotationConfigApplicationContext() {
- AnnotationConfigApplicationContext context =
- new AnnotationConfigApplicationContext(Config.class);
-
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- System.out.println(context.getBean(Bean2.class).getBean1());
- }
-
- @Configuration
- static class Config {
- @Bean
- public Bean1 bean1() {
- return new Bean1();
- }
-
- @Bean
- public Bean2 bean2(Bean1 bean1) {
- Bean2 bean2 = new Bean2();
- bean2.setBean1(bean1);
- return bean2;
- }
- }
结果:发现该容器已经配置了解析@Configuration,@Autowire,@Resourse等注解的后处理器
- 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
- a02Application.Config
- bean1
- bean2
- com.itheima.a02.A02Application$Bean1@6025e1b6
Spring boot 中 servlet web 环境容器,基于 java 配置类来创建, 用于 web 环境
- private static void testAnnotationConfigServletWebServerApplicationContext() {
- AnnotationConfigServletWebServerApplicationContext context =
- new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
- }
-
- @Configuration
- static class WebConfig {
- //内嵌一个基于servlet的Web容器,即提供web服务器的组件
- @Bean
- public ServletWebServerFactory servletWebServerFactory(){
- return new TomcatServletWebServerFactory();
- }
- //前端控制器
- @Bean
- public DispatcherServlet dispatcherServlet() {
- return new DispatcherServlet();
- }
- //Servlet是运行在Tomcat服务器上的,需要将他们两个关联
- //将DispatcherServlet注册到Tomcat服务器
- @Bean
- public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
- //让除了jsp的所有请求都先经过DispatcherServlet
- return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
- }
- //以 /开头可以将它的名称作为访问路径
- @Bean("/hello")
- //注意:是org.springframework.web.servlet.mvc.Controller接口,而不是注解
- public Controller controller1() {
- return new Controller() {
- @Override
- public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
- response.getWriter().print("hello");
- return null;
- }
- };
- }
- }
结果:发现该容器已经配置了解析@Configuration,@Autowire,@Resourse注解的后处理器,并且我们可以通过 localhost:8080/hello进行访问
- 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
- a02Application.WebConfig
- servletWebServerFactory
- dispatcherServlet
- registrationBean
- /hello
学到了什么?
- 常见的 ApplicationContext 容器实现
- 内嵌容器、DispatcherServlet 的创建方法、作用