本人在互联网摸爬滚打至今(23年)6年了,
平时有写博客的习惯,这个习惯是从大学的时候开始的,
目前主要关注java领域相关的技术,python也有涉及,
写Spring专题是因为Spring确实很重要,在目前这个开发模式下。
由于工作强度的问题,之前一直是拉Spring源代码写注释的方式去分析源码,并没有进行总结和归纳,这样会导致时间长了之后忘记相关内容,重新又看一遍,非常耗时。
然后就有了这个专题,希望来到这里的读者能找到点有用的东西,也希望有兴趣的朋友一起交流。Spring的源码如果有小伙伴想要的话,可以留下邮箱。

以下是一些个人建议
所有的源码分析都将从下述代码开始。
public class QhyuApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AopConfig.class);
}
}
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation;
import java.util.Arrays;
import java.util.function.Supplier;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.metrics.StartupStep;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Standalone application context, accepting component classes as input —
* in particular {@link Configuration @Configuration}-annotated classes, but also plain
* {@link org.springframework.stereotype.Component @Component} types and JSR-330 compliant
* classes using {@code javax.inject} annotations.
*
* Allows for registering classes one by one using {@link #register(Class...)}
* as well as for classpath scanning using {@link #scan(String...)}.
*
*
In case of multiple {@code @Configuration} classes, {@link Bean @Bean} methods
* defined in later classes will override those defined in earlier classes. This can
* be leveraged to deliberately override certain bean definitions via an extra
* {@code @Configuration} class.
*
*
See {@link Configuration @Configuration}'s javadoc for usage examples.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 3.0
* @see #register
* @see #scan
* @see AnnotatedBeanDefinitionReader
* @see ClassPathBeanDefinitionScanner
* @see org.springframework.context.support.GenericXmlApplicationContext
*/
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
/**
* Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
*/
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 以前的源码我记得有一个allowCircleRefrence(true)允许循环依赖的东西,现在不开放了?
// this方法用来准备AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner和,用于register读取definition
this();
// 这里我手动加的,之前的版本是有的,现在移除了,不影响
setAllowCircularReferences(true);
// 注册我们的启动class
register(componentClasses);
refresh();
}
/**
* Create a new AnnotationConfigApplicationContext, scanning for components
* in the given packages, registering bean definitions for those components,
* and automatically refreshing the context.
* @param basePackages the packages to scan for component classes
*/
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
/**
* Propagate the given custom {@code Environment} to the underlying
* {@link AnnotatedBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
/**
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
* Default is {@link AnnotationBeanNameGenerator}.
*
Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
/**
* Set the {@link ScopeMetadataResolver} to use for registered component classes.
* The default is an {@link AnnotationScopeMetadataResolver}.
*
Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
*/
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
//---------------------------------------------------------------------
// Implementation of AnnotationConfigRegistry
//---------------------------------------------------------------------
/**
* Register one or more component classes to be processed.
* Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
* @see #scan(String...)
* @see #refresh()
*/
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
.tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
}
/**
* Perform a scan within the specified base packages.
* Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param basePackages the packages to scan for component classes
* @see #register(Class...)
* @see #refresh()
*/
@Override
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
.tag("packages", () -> Arrays.toString(basePackages));
this.scanner.scan(basePackages);
scanPackages.end();
}
//---------------------------------------------------------------------
// Adapt superclass registerBean calls to AnnotatedBeanDefinitionReader
//---------------------------------------------------------------------
@Override
public <T> void registerBean(@Nullable String beanName, Class<T> beanClass,
@Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
this.reader.registerBean(beanClass, beanName, supplier, customizers);
}
}
当涉及到 Spring 源码分析时,以下是一些常用的参考资料,可以帮助你更好地理解和分析 Spring 框架的内部实现:
官方文档和源码:Spring 官方网站提供了详细的文档和源码,包括框架的核心模块、扩展模块和示例代码。官方文档对于理解 Spring 的设计和用法非常有帮助,源码则提供了直接的参考和实例。
Spring 源码解析系列博客:有一些知名的博主和开发者经常分享关于 Spring 源码解析的系列文章,例如《Spring 源码深度解析》系列、《Spring Framework 源码解析》系列等。这些博客通常会深入讲解 Spring 框架的核心组件和关键实现细节。
《Spring 揭秘》:这是一本由 Rod Johnson 撰写的经典书籍,对 Spring 框架的设计思想和内部实现进行了详细解析。尽管该书已有些年头,但仍然对理解 Spring 的核心概念和原理具有很大帮助。
《Spring in Action》:这是一本广为人知的 Spring 入门书籍,其中包含了对 Spring 源码的解析和说明。尽管对于深入源码分析可能不够详细,但对于初学者来说是一个很好的起点。
GitHub 上的 Spring 源码分析项目:有一些开源项目专门致力于对 Spring 源码的分析和解读,这些项目通常包含了详细的文档、示例代码和实践经验。你可以在 GitHub 上搜索相关项目,如 “spring-framework-analysis” 等。
当对 Spring 源码进行分析后,你可以根据你的分析内容和结论,对所分析的源码进行总结。以下是一些可能的总结要点,供参考:
概述:简要介绍所分析的 Spring 源码模块或功能的作用和重要性。
核心设计原则:阐述 Spring 源码中所遵循的核心设计原则,如依赖注入(DI)、面向切面编程(AOP)等。解释这些原则如何帮助 Spring 实现松耦合、可扩展和可测试的应用开发。
核心组件:列举并描述 Spring 源码中的核心组件,如 BeanFactory、ApplicationContext、BeanPostProcessor、AOP Proxy 等。解释它们的作用、关系和实现原理。
生命周期管理:探讨 Spring 源码中的 Bean 生命周期管理机制,包括 Bean 的初始化、销毁和后置处理等阶段。解释这些机制如何通过回调方法和扩展点实现,并介绍 Spring 源码中的关键类和接口。
依赖注入:深入分析 Spring 源码中的依赖注入实现方式,包括基于 XML 配置文件、注解和 Java 配置的三种方式。解释 Spring 源码是如何解析和管理依赖关系,并实现对象之间的解耦。
AOP 支持:研究 Spring 源码中的 AOP 支持,包括切面、切点、通知和代理等概念。解释 Spring 是如何通过动态代理和字节码增强实现 AOP 功能的,并探讨关键的类和接口。
事务管理:探索 Spring 源码中的事务管理机制,包括声明式事务和编程式事务。解释 Spring 是如何通过 AOP 和事务管理器来实现事务的控制和管理。
其他模块和扩展:介绍其他值得关注的 Spring 源码模块和扩展,如 Spring MVC、Spring Security、Spring Data 等。解释它们的作用、设计思想和关键类。
总结和收获:总结你对 Spring 源码的分析和理解,强调你在这个过程中所获得的知识和经验。提出你对 Spring 源码设计和实现的评价,以及你认为可以改进的方面。
通过对 Spring 源码的分析和总结,你可以加深对 Spring 框架的理解,并对其核心功能和设计原则有更深入的认识。同时,你也可以从中获得对软件工程和设计模式的启发,以及在实际应用开发中的指导意义。
在进行 Spring 源码分析时,以下是一些常用的工具,可以帮助你更好地理解和调试 Spring 框架的内部实现:
IDE(集成开发环境):使用一款功能强大的 IDE,如 IntelliJ IDEA、Eclipse 或 Visual Studio Code,可以大大提高你分析和调试 Spring 源码的效率。这些 IDE 提供了代码导航、调试功能和代码搜索等工具,使你能够更方便地浏览和理解源码。
调试器:利用 IDE 提供的调试功能,你可以在代码中设置断点并逐步执行,观察变量的值和方法的调用流程。这对于理解 Spring 框架内部的工作原理和调用链非常有帮助。
日志工具:Spring 框架大量使用日志输出来记录关键信息和调试信息。你可以配置日志工具,如 Logback、Log4j 或 SLF4J,以获得 Spring 框架在运行时输出的详细日志信息。这些日志信息可以帮助你跟踪代码执行流程和排查问题。
反编译工具:有时,如果你希望分析 Spring 源码中的特定类或方法的实现细节,可以使用反编译工具来将编译后的字节码还原为可读的源代码。常用的反编译工具包括 JD-GUI、Bytecode Viewer 等。
Git 版本控制:Spring 框架的源码托管在 Git 仓库中,你可以使用 Git 工具来获取源码并进行版本管理。这样可以方便地切换不同的版本,追溯代码变更历史,并对比不同版本之间的差异。
测试工具:编写单元测试和集成测试是分析 Spring 源码的重要手段之一。使用 JUnit、Mockito、Spring Test 等测试框架,你可以编写针对 Spring 源码中特定类或方法的测试用例,以验证其行为和功能。
除了上述工具,还有一些其他辅助工具和插件可以帮助你更好地进行 Spring 源码分析,如代码生成工具、静态代码分析工具等。根据你的具体需求和习惯选择适合的工具,并灵活运用它们来辅助你的源码分析工作。