介绍
代码仓库地址:https://gitee.com/CandyWall/spring-source-study 跟着做学习笔记,这个笔记和视频内容的项目名称和代码略有不同。我把49个代码的每个代码拆分成独立的springboot项目,项目名称尽可能知名,是基于我自己的考虑,代码已经验证,仅供参考。
视频教程地址:https://www.bilibili.com/video/BV1P44y1N7QG
注:
1. 每个对应一个二级标题,每个三级标题都是用子项目名命名的,与我的代码仓库项目一一对应; 2. 使用代码lombok插件来简化了Bean中的get()、set()使用方法和日志记录lombok的@Slf4j注解。
每个子项目对应的视频链接和一些重要内容的笔记
第一讲 BeanFactory
与ApplicationContext
区别与联系
spring_01_beanfactory_applicationcontext_differences_connections
p1 000-Spring高级49讲-导学
p2 001-第一讲-BeanFactory与ApplicationContext_1
测试代码:
@SpringBootApplication @Slf4j public class A01Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args); // class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext System.out.println(context.getClass()); } }
到底什么是BeanFactory
-
它是
ApplicationContext
的父接口鼠标选中
ConfigurableApplicationContext
,按Ctrl Shift U
或者Ctrl Alt U
打开类图,可以看到ApplicationContext
父接口是BeanFactory
-
它才是
Spring
主要的核心容器ApplicationContext
实现都 [组合]他的功能打印
context.getClass()
,可以看到SpringBoot返回启动程序ConfigurableApplicationContext
具体实现类是AnnotationConfigServletWebServerApplicationContext
ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args); // org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext System.out.println/span>(context.getClass());
按图索骥,
AnnotationConfigServletWebServerApplicationContext
又间接继承了GenericApplicationContext
,在这个类里面可以找到beanFactory
作为成员变量出现。
p3 002-第一讲-BeanFactory功能
BeanFactory
接口中的方法
查看springboot
默认的ConfigurableApplicationContext
类中的BeanFactory
的实际类型
ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());
从打印结果可以了解到实际类型为DefaultListableBeanFactory
,所以这里以BeanFactory
的一个实现类DefaultListableBeanFactory
作为出发点,进行分析。
它的类图如下:
这里我们暂且不细看DefaultListableBeanFactory
,先看DefaultListableBeanFactory
的父类DefaultSingletonBeanFactory
,先选中它,然后按F12
,可以跳转到对应的源码,可以看到有个私有的成员变量singletonObjects
这里通过反射的方法来获取该成员变量,进行分析
先补充一下反射获取某个类的成员变量的步骤:
获取成员变量,步骤如下:
获取Class对象
获取构造方法
通过构造方法,创建对象
获取指定的成员变量(私有成员变量,通过(boolean flag)方法暴力访问)
通过方法,给指定对象的指定成员变量赋值或者获取值
public void set(Object obj, Object value)
在指定对象obj中,将此 Field 对象表示的成员变量设置为指定的新值
public Object get(Object obj)
返回指定对象obj中,此 Field 对象表示的成员变量的值
代码如下:
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
// 设置私有变量可以被访问
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());
map.entrySet().stream().filter(entry -> entry.getKey().startsWith("component")).forEach(System.out::println);
这里singletonObjects.get(beanFactory)
为什么要传一个ConfigurableListableBeanFactory
的变量进去呢?打印了这个beanFactory
的实际类型为DefaultListableBeanFactory
,查看其类图,可以了解到该类也实现了DefaultSingletonBeanRegistry
接口,所以这里反射获取某个类的成员变量的get()
方法中可以作为参数传进来。
p4 003-第一讲-ApplicationContext功能1
ApplicationContext
比 BeanFactory
多点啥?
多实现了四个接口:
MessageSource
: 国际化功能,支持多种语言ResourcePatternResolver
: 通配符匹配资源路径EnvironmentCapable
: 环境信息,系统环境变量,*.properties
、*.application.yml
等配置文件中的值ApplicationEventPublisher
: 发布事件对象
-
MessageSource
在
resources
目录下创建四个文件messages.propertes
、messages_en.properties
、messages_ja.properties
、messages_zh.properties
,然后分别在四个文件里面定义同名的key
,比如在message_en.properties
中定义hi=hello
,在messages_ja.propertes
中定义hi=こんにちは
,在messages_zh
中定义hi=你好
,这样在代码中就可以根据这个**key hi
语言类型**获取不同的value
了。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));
运行结果如下:
p5 004-第一讲-ApplicationContext功能2,3
-
ResourcePatternResolver
例1:获取类路径下的
messages
开头的配置文件Resource[] resources = context.getResources("classpath:messages*.properties"); for (Resource resource : resources) { System.out.println(resource); }
例2:获取
spring
相关jar
包中的spring.factories
配置文件resources = context.getResources("classpath*:META-INF/spring.factories"); for (Resource resource : resources) { System.out.println(resource); }
-
EnvironmentCapable
获取系统环境变量中的
java_home
和项目的application.yml
中的server.port
属性System.out.println(context.getEnvironment().getProperty("java_home")); System.out.println(context.getEnvironment().getProperty("server.port"));
p6 005-第一讲-ApplicationContext功能4
-
ApplicationEventPublisher
定义一个类,继承自
ApplicationEvent
类public class UserRegisteredEvent extends ApplicationEvent { public UserRegisteredEvent(Object source) { super(source); } }
再定义一个类,用于监听用户注册事件,类头上需要加
@Component
注解,将该类交给spring
管理,定义一个处理事件的方法,参数类型为件类的对象,方法头上需要加上@EventListener
注解@Component @Slf4j public class UserRegisteredListener { @EventListener public void userRegist(UserRegisteredEvent event) { System.out.println("UserRegisteredEvent..."); log.debug("{}", event); } }
接着再定义一个类,里面有个
register(String username, String password)
方法可以完成用户的注册,注册完毕后发布一下。@Component @Slf4j public class UserService { @Autowired private ApplicationEventPublisher context; public void register(String username, String password) { log.debug("新用户注册,账号:" + username + ",密码:" + password); context.publishEvent(new UserRegisteredEvent(this)); } }
最后在
Springboot
启动类中调用一下UserService
里面的register()
方法注册一个新用户,UserRegisteredListener
中就能处理这个用户注册完毕的事件,实现了UserService
类和UserRegisteredListener
类的解耦。UserService userService = context.getBean(UserService.class); userService.register("张三", "123456");
p7 006-第一讲-小结
第二讲 BeanFactory
和 ApplicationContext
类的重要实现类
spring_02_01_beanfactory_impl
p8 007-第二讲-BeanFactory实现
p9 008-第二讲-BeanFactory实现
p10 009-第二讲-BeanFactory实现-后处理器排序
DefaultListableBeanFactory
接着第一讲中的内容,执行以下代码,可以了解到
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 查看实际类型
// class org.springframework.beans.factory.support.DefaultListableBeanFactory
System.out.println(beanFactory.getClass());
ConfigurableApplicationContext
类内部组合的BeanFactory
实际类型为DefaultListableBeanFactory
,spring
底层创建实体类就是依赖于这个类,所以它是BeanFactory
接口最重要的一个实现类,下面使用这个类,模拟一下spring
使用DefaultListableBeanFactory
类创建其他实体类对象的过程。
测试代码如下:
package top.jacktgq.spring_02_beanfactory_impl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.stream.Collectors;
/** * @Author CandyWall * @Date 2022/3/24--21:20 * @Description */
public class TestBeanFactory {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 从bean工厂中取出BeanFactory的后处理器,并且执行这些后处理器
// BeanFactory 后处理器主要功能,补充了一些 bean 的定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
System.out.println(beanFactoryPostProcessor);
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// 打印BeanFactory中Bean
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
// 从BeanFactory中取出Bean1,然后再从Bean1中取出它依赖的Bean2
// 可以看到结果为null,所以@Autowired注解并没有被解析
// Bean1 bean1 = beanFactory.getBean(Bean1.class);
// System.out.println(bean1.getBean2());
// 要想@Autowired、@Resource等注解被解析,还要添加Bean的后处理器,可以针对Bean的生命周期的各个阶段提供扩展
// 从bean工厂中取出Bean的后处理器,并且执行这些后处理器
// BeanFactory 后处理器主要功能,补充了一些 bean 的定义
// beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
// beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values());
// 改变Bean后处理器加入BeanFactory的顺序
// 写法1:
// ArrayList<BeanPostProcessor> list = new ArrayList<>(beanFactory.getBeansOfType(BeanPostProcessor.class).values());
// Collections.reverse(list);
// beanFactory.addBeanPostProcessors(list);
// 写法2:
beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).collect(Collectors.toCollection(ArrayList::new)));
// 准备好所有单例,get()前就把对象初始化好
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
/** * 学到了什么: * a. beanFactory 不会做的事 * 1. 不会主动调用BeanFactory的后处理器 * 2. 不会主动添加Bean的后处理器 * 3. 不会主动初始化单例 * 4. 不会解析BeanFactory,还不会解析 ${}, #{} * * b. Bean后处理器会有排序的逻辑 */
System.out.println(bean1.getInter());
}
@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();
}
}
@Slf4j
static class Bean1 {
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
public Bean1() {
log.debug("构造 Bean1()");
}
}
@Slf4j
static class Bean2 {
public Bean2() {
log.debug("构造 Bean2()");
}
}
interface Inter {
}
@Slf4j
static class Bean3 implements Inter {
public Bean3() {
log.debug("构造 Bean3()");
}
}
@Slf4j
static class Bean4 implements Inter {
public Bean4() {
log.debug("构造 Bean4()");
}
}
}
总结:
-
beanFactory 不会做的事
-
不会主动调用BeanFactory的后处理器
-
不会主动添加Bean的后处理器
-
不会主动初始化单例
-
不会解析BeanFactory,还不会解析 ${}, #{}
-
-
Bean后处理器会有排序的逻辑
先定义一个接口Inter,再定义两个Bean,名称分别为Bean3和Bean4,都继承Inter,接着在Config中通过@Bean注解将Bean3和Bean4都加进Bean工厂中,然后在Bean1中定义一个Inter对象,通过@Autowired注解将实现类注入进来。
@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(); } } @Slf4j static class Bean1 { @Autowired private Bean2 bean2; public Bean2 getBean2() { return bean2; } @Autowired @Resource(name = "bean4") private Inter bean3; public Inter getInter() { return bean3; } public Bean1() { log.debug("构造 Bean1()"); } } @Slf4j static class Bean2 { public Bean2() { log.debug("构造 Bean2()"); } } interface Inter { } @Slf4j static class Bean3 implements Inter { public Bean3() { log.debug("构造 Bean3()"); } } @Slf4j static class Bean4 implements Inter { public Bean4() { log.debug("构造 Bean4()"); } }
如果把以
Inter
接口声明的变量名定义为inter
,@Autowired
注解首先会**根据名称(byName)根据类型(byType)**进行匹配,发现Bean3和Bean4都实现了Inter接口,会报无法自动装配的错误。所以为了避免这种错误,以
Inter
接口声明的变量名只能为bean3
或者bean4
,这里把以Inter
接口声明的变量名定义为bean3
,