笔记参考B站黑马程序员视频:spring原理
pom.xml配置如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1.BeanFactory接口
打开一个springboot项目的启动类 可以看到启动类的run方法是有返回值的

ConfigurableApplicationContext 是 Spring 框架中的一个接口,扩展了 ApplicationContext 接口。 ctrl+Alt+U打开类图

如下


ApplicationContext是间接继承BeanFactory的 BeanFactory才是 Spring 的核心容器,主要的 ApplicationContext 实现都组合了它的功能 比如getBean方法

实际就是调用内部组合了BeanFactory的方法


BeanFactory的默认实现是DefaultListableBeanFactory

类图如下:

DefaultSingletonBeanRegistry 是 Spring 框架中用于管理单例 bean 的默认实现类。
在 Spring 容器中,bean 可以配置为单例(singleton)或原型(prototype)。对于单例 bean,Spring 将仅创建一个实例,并在需要时重复使用该实例。
DefaultSingletonBeanRegistry 负责跟踪和管理这些单例 bean 的创建和获取。
在类图上选中类,点击F4就可以跳转到源码
singletonObjects 是 DefaultSingletonBeanRegistry 类中用于缓存已经创建的单例 bean 实例。
这个缓存是一个 ConcurrentHashMap,它使用 bean 的名称作为键,bean 实例作为值。

2.ApplicationContext接口
ApplicationContext 提供了对应用程序中所有 bean 的管理功能,包括创建、配置、初始化和销毁 bean。
主要功能在这四个类中:
- ResourcePatternResolver:用于根据路径模式加载多个资源。
- ApplicationEventPublisher:用于发布应用事件。
- EnvironmentCapable:指示对象能够访问 Environment,获取环境属性。
- MessageSource:用于解析国际化消息。

1. MessageSource
MessageSource 支持国际化消息解析 在对应文件配置

这里存放通用的

这是英文

日文,当然可以写成日文

中文

ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
System.out.println(context.getMessage("dreams", null, Locale.CHINA));
System.out.println(context.getMessage("dreams", null, Locale.ENGLISH));
System.out.println(context.getMessage("dreams", null, Locale.JAPANESE));

2.ApplicationEventPublisher
通过 ApplicationEventPublisher 支持事件发布和监听。 我们需要先创建一个事件类
package com.dreams.a01;
import org.springframework.context.ApplicationEvent;
public class UserRegisteredEvent extends ApplicationEvent {
public UserRegisteredEvent(Object source) {
super(source);
}
}发送
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args); context.publishEvent(new UserRegisteredEvent(context));
发布 UserRegisteredEvent 事件,由 Event02类自动进行处理 由 Event02类接收
package com.dreams.a01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class Event02 {
private static final Logger log = LoggerFactory.getLogger(Event02.class);
@EventListener
public void send(UserRegisteredEvent event) {
log.debug("{}", event);
log.debug("发送短信");
}
}
package com.dreams.a01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class Event01 {
private static final Logger log = LoggerFactory.getLogger(Event01.class);
@Autowired
private ApplicationEventPublisher context;
public void register() {
log.debug("用户注册");
context.publishEvent(new UserRegisteredEvent(this));
}
}然后在启动类加入注册代码
context.getBean(Event01.class).register();
运行:

3.ResourcePatternResolver
通过ResourcePatternResolver支持访问各种类型的资源,如文件、URL 等。 对应方法是getResources 加载符合指定路径模式的所有资源
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
4.EnvironmentCapable
通过 EnvironmentCapable接口提供对环境变量和属性的访问。 对应方法是getEnvironment()
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));
3.BeanFactory实现
DefaultListableBeanFactory 是 BeanFactory 接口的默认实现。 定义一些配置:
@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();
}
}
interface Inter {
}
static class Bean3 implements Inter {
}
static class Bean4 implements Inter {
}
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;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}根据上面的代码我们可以手动注册一个名为 “config” 的 Bean 定义 常用方法;
- BeanDefinitionBuilder 是一个用于构建 Bean 定义的实用程序类。
- genericBeanDefinition(Config.class) 表示创建一个通用的 Bean 定义,指定了 Bean 的类型为 Config。
- setScope(“singleton”) 表示将 Bean 的作用域设置为 Singleton单例模式,即在容器中仅存在一个实例。
- 使用 beanFactory.registerBeanDefinition() 方法注册了名为 “config” 的 Bean 定义,其中包含了上面定义的配置信息。
实例代码如下:
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
但是上面的配置了不止一个Bean,如下:
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
//......
}也就是对@Bean等注解的解析并不在该BeanFactory类。
AnnotationConfigUtils.registerAnnotationConfigProcessors() 方法,向 BeanFactory 添加一些常用的后处理器,这些后处理器用于处理注解配置。 然后还需要获取并执行所有注册的 BeanFactoryPostProcessor(Bean工厂处理器,下面输出的第一个处理器,但是第二第三不是),对 BeanFactory 中的 Bean 进行处理。
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 此时还没有处理
System.out.println("此时还没有处理 :");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
// BeanFactoryPostProcessor后处理器主要功能为补充了一些 bean 定义
// 获取并执行所有注册的 BeanFactoryPostProcessor,对 BeanFactory 中的 Bean 进行处理。
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream()
.forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
System.out.println("\n处理完成 :");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
这些是 Spring 框架中常用的内部后处理器。
- org.springframework.context.annotation.internalConfigurationAnnotationProcessor: 这个后处理器用于处理配置类上的注解,例如 @Configuration 注解。它会扫描并解析这些注解,将配置类转换为相应的 Bean 定义。
- org.springframework.context.annotation.internalAutowiredAnnotationProcessor: 这个后处理器用于处理自动装配的注解,例如 @Autowired 和 @Resource 注解。它会扫描并解析这些注解,完成依赖注入的操作。
- org.springframework.context.annotation.internalCommonAnnotationProcessor: 这个后处理器用于处理通用的注解,例如 JSR-250 规范中定义的注解,如 @PostConstruct 和 @PreDestroy,或者还有@Resource,它会扫描并解析这些注解,执行相应的初始化和销毁方法。
- org.springframework.context.event.internalEventListenerProcessor: 这个后处理器用于处理事件监听器的注解,例如 @EventListener 注解。它会扫描并解析这些注解,将事件监听器注册到事件发布器中,以便在对应的事件发生时触发相应的处理逻辑。
- org.springframework.context.event.internalEventListenerFactory: 这个后处理器用于创建事件监听器的适配器,使得事件监听器能够被正确地触发。它会根据监听器的类型和方法签名,创建适配器实例,并将其注册到事件发布器中。
我们只使用了第一个处理器,所以这时还没有执行自动注入
Bean2 bean2 = beanFactory.getBean(Bean1.class).getBean2(); System.out.println(bean2 != null? bean2 : "未注入");

再添加上BeanPostProcessor处理器
// BeanFactory 后处理器主要功能,补充了一些 bean 定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.forEach(beanPostProcessor -> {
System.out.println(">>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
Bean2 bean2 = beanFactory.getBean(Bean1.class).getBean2();
System.out.println(bean2 != null? "注入成功 对象 :" + bean2 : "未注入");这两个就是BeanPostProcessor。

默认是调用时才加载,也就是说虽然我们添加了处理器,但是不会去加载,而是等到比如调用getBean方法,才加载 注释上面调用的getBean方法,加入以下代码
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
加入下面代码
// 准备好所有单例
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
如果一个属性同时使用了 @Autowired 和 @Resource 注解,通常情况下@Autowired 注解会生效。
具体来说,这是因为 @Resource 注解是由 CommonAnnotationBeanPostProcessor 处理的,而 @Autowired 注解是由 AutowiredAnnotationBeanPostProcessor 处理的。
如上图,在 Spring 的默认配置下,AutowiredAnnotationBeanPostProcessor优先级高于CommonAnnotationBeanPostProcessor ,因此@Autowired 注解会被优先处理。 如果想要更改优先级,加入:
.sorted(beanFactory.getDependencyComparator())
代码如下:
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println(">>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
// 准备好所有单例
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
beanFactory.getDependencyComparator() 方法用于获取一个 Comparator 对象,该对象可以用来对 Bean 进行排序。 上面我们使用添加后处理器的方法

进入源码


4.ApplicationContext实现
ApplicationContext 有多种常用的实现类: ClassPathXmlApplicationContext:从类路径下的 XML 配置文件中加载上下文定义,适合相对独立的应用程序。
// 较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}需要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">
<!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
<bean id="bean1" class="com.dreams.a02.A02.Bean1"/>
<!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
<bean id="bean2" class="com.dreams.a02.A02.Bean2">
<!-- 依赖注入, 建立与 bean1 的依赖关系 -->
<property name="bean1" ref="bean1"/>
</bean>
</beans>
如果xml配置了
<context:annotation-config/>
就不用在xml一个一个Bean的注入了,底层就是加入了后置处理器,可以看到输出了处理器

FileSystemXmlApplicationContext:从文件系统中的 XML 配置文件中加载上下文定义,也适合相对独立的应用程序。
// 基于磁盘路径下 xml 格式的配置文件来创建
private static void testFileSystemXmlApplicationContext() {
FileSystemXmlApplicationContext context =
new FileSystemXmlApplicationContext(
"src\\main\\resources\\a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}AnnotationConfigApplicationContext:通过 Java 注解配置来加载上下文定义,适合基于注解的 Spring 应用程序。非web的springboot使用这种
// 较为经典的容器, 基于 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;
}
}
static class Bean1 {
}
static class Bean2 {
private Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}可以看到自动加入了处理器。

AnnotationConfigServletWebServerApplicationContext基于 java 配置类来创建, 用于 web 环境,它继承自 GenericWebApplicationContext,这也是springboot的web底层使用的ApplicationContext
// 较为经典的容器, 基于 java 配置类来创建, 用于 web 环境
private static void testAnnotationConfigServletWebServerApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}还要配置:
servletWebServerFactory(): 定义了一个 Servlet Web 服务器工厂的 Bean,并返回了一个 TomcatServletWebServerFactory 的实例。(就是内嵌的tomcat)
dispatcherServlet(): 定义了一个 DispatcherServlet 的 Bean,并返回了一个 DispatcherServlet 的实例。
registrationBean(DispatcherServlet dispatcherServlet): 定义了一个 DispatcherServletRegistrationBean 的 Bean,用于将 DispatcherServlet 注册到根路径(“/”)。
@Configuration
static class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
5.关联
beanFactory解析xml就会调用XmlBeanDefinitionReader来解析xml
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("a02.xml"));
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
6.BeanFactory补充
在 Spring 发展阶段中重要,但目前已经很鸡肋的接口 FactoryBean 的使用要点
- 它的作用是用制造创建过程较为复杂的产品,如 SqlSessionFactory,但 @Bean 已具备等价功能
- 使用上较为古怪,一不留神就会用错
被 FactoryBean 创建的产品
- 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会走
- 唯有后初始化的流程会走, 也就是产品可以被代理增强
- 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个factoryBeanObjectCache 成员中。
- 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象
示例代码: Bean2
package com.dreams.demo43;
import org.springframework.stereotype.Component;
@Component
public class Bean2 {
}Bean1 注意这里并没有@Component注解,也就是不是配置类
package com.dreams.demo43;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
public class Bean1 implements BeanFactoryAware {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("setBean2({})", bean2);
this.bean2 = bean2;
}
public Bean2 getBean2() {
return bean2;
}
@PostConstruct
public void init() {
log.debug("init");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.debug("setBeanFactory({})", beanFactory);
}
}Bean1FactoryBean 将该工厂bean声明为 Spring 容器中的一个组件,并指定了它的名字为 “bean1″。
Bean1FactoryBean 类实现了 FactoryBean<Bean1> 接口,这意味着它是一个工厂bean,负责生产 Bean1 类的实例。
FactoryBean 接口方法实现
- getObjectType() 方法: 指定了工厂bean 生产的对象类型,在这里是 Bean1.class。这告诉 Spring 在需要自动装配时,应该使用哪种类型。
- isSingleton() 方法: 指定了由该工厂bean 创建的 Bean1 实例是否是单例。在这里,返回 true 表示 Bean1 是单例的,即 Spring 容器中只有一个 Bean1 的实例。
- getObject() 方法: 这是工厂bean 的核心方法,用于创建并返回 Bean1 的实例。在这里,简单地创建一个新的 Bean1 对象
package com.dreams.demo43;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component("bean1")
public class Bean1FactoryBean implements FactoryBean<Bean1> {
private static final Logger log = LoggerFactory.getLogger(Bean1FactoryBean.class);
// 决定了根据【类型】获取或依赖注入能否成功
@Override
public Class<?> getObjectType() {
return Bean1.class;
}
// 决定了 getObject() 方法被调用一次还是多次
@Override
public boolean isSingleton() {
return true;
}
@Override
public Bean1 getObject() throws Exception {
Bean1 bean1 = new Bean1();
log.debug("create bean: {}", bean1);
return bean1;
}
}Bean1的后置处理器
package com.dreams.demo43;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class Bean1PostProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(Bean1PostProcessor.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("bean1") && bean instanceof Bean1) {
log.debug("before [{}] init", beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("bean1") && bean instanceof Bean1) {
log.debug("after [{}] init", beanName);
}
return bean;
}
}main方法
package com.dreams.demo43;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
Bean1 bean1 = (Bean1) context.getBean("bean1");
Bean1 bean2 = (Bean1) context.getBean("bean1");
Bean1 bean3 = (Bean1) context.getBean("bean1");
System.out.println(bean1);
System.out.println(bean2);
System.out.println(bean3);
System.out.println(context.getBean(Bean1.class));
System.out.println(context.getBean(Bean1FactoryBean.class));
System.out.println(context.getBean("&bean1"));
context.close();
}
}可以看到按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象,而且Bean1类是由工厂创建的,Bean1的@Autowired、@PostConstruct、Aware回调都失效了。而Bean后处理器只会走初始化后处理postProcessAfterInitialization,初始化后处理的例子就是代理增强了,也就是代理可以生效。

7.参考
黑马程序员:spring


