Раньше я не осознавал важности чтения превосходного исходного кода фреймворка, пока не прочитал исходный код mybatis, spring IOC, AOP, springMVC и не изучил много низкоуровневых знаний, таких как самоанализ отражения java, динамический прокси jdk , cglib dynamic proxy, я понял, что в исходном коде используются различные шаблоны проектирования, что делает фреймворк очень мощным и расширяемым.В то время я понял, что фреймворк еще и очень красивый. Без дальнейших церемоний, давайте начнем наше путешествие по исходному коду SpringIOC.
Версия исходного кода, используемая в этой статье, — 5.2.x. Чтобы нам лучше понять springIOC, мы используем метод xml, и большая часть фактической разработки осуществляется в виде аннотаций.Опыт подсказывает мне, что с точки зрения понимания исходного кода конфигурация xml является лучшей.
Предлагаемый источник для чтения: перейти на официальный сайт, чтобы загрузить последний исходный код, увидеть сияние или просто не выдержать, прежде чем я понес убытки, так как я смогу прочитать исходный код, чтобы понять, это было действительно наивно, прочитать несколько страниц, чтобы бросить, потому что не читал.
В этой статье предполагается, что у читателя уже есть основы, связанные со Spring, например, как построить проект, представить зависимости, связанные со Spring, и использовать модульное тестирование.
введение
Самая большая трудность в чтении исходного кода заключается в том, что трудно найти вход.Опыт подсказывает нам, что метод исходного кода, который мы обычно используем, является входом в чтение, что тесно связано с нашей обычной разработкой.
Создайте проект maven, добавьте связанные зависимости и используйте модульные тесты для проверки процесса получения bean-компонентов.
Давайте посмотрим, как мы обычно используем SpringIOC:
Вот оригинальный способ, которым мы обычно получаем боб:
public class TestSpring {
@Test
public void testSpring() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
Student student = (Student) ctx.getBean("student");
System.out.println(student);
}
}
Создайте папку в файле Resource Application.xml, обычно называемый Application.xml или Application-XXX.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="student" class="com.sjc.spring.po.Student">
<!-- String类型 -->
<property name="name" value="jiangcong"></property>
<!-- Integer类型 -->
<property name="age" value="18"></property>
<!-- 引用类型 -->
<property name="course" ref="course"></property>
</bean>
<!-- 该类有一个初始化方法 -->
<bean id="course" class="com.sjc.spring.po.Course"
init-method="init">
<!-- String类型 -->
<property name="name" value="spring"></property>
</bean>
</beans>
Студенческий класс
public class Student {
private String name;
private Integer age;
private Course course;
//... 省略getter/setter方法
}
Класс курса
public class Course {
private String name;
//... 省略getter/setter方法
}
Пример очень простой, но его достаточно, чтобы перейти к теме этой статьи, изучить, как контейнер Spring устанавливает файл конфигурации и как создать для нас экземпляр bean-компонента, чтобы мы могли получить экземпляр класса Student через getBean («студент»), таким образом, поймите основные IOC и DI в весне.
Прежде чем начать читать исходный код, давайте сначала представим важные интерфейсы Spring, Здесь не требуется, чтобы вы освоили его, но когда вы входите в часть чтения исходного кода, у вас возникает впечатление, а затем вы можете найти знание этой части.
Весеннее важное введение в интерфейс
Система наследования BeanFactory
Глядя на эти замысловатые диаграммы классов, мы не можем отделаться от ощущения, что Spring огромен. Так почему же Spring определяет так много интерфейсов? Поскольку у каждого интерфейса есть свой случай использования, у каждого интерфейса есть определенные обязанности, но они не мешают друг другу, что является принципом изоляции интерфейса в шаблоне проектирования. Только вдумайтесь, если все эти функции реализовать в одном-двух интерфейсах, бардака не будет.
Основные функции основных классов описаны ниже:
BeanFactory:
Интерфейс в основном определяет базовое поведение контейнера IOC, например, получение bean-компонентов в соответствии с различными условиями. Здесь используется заводская выкройка.
ListableBeanFactory:
Как видно из названия, особенность этого интерфейса в том, что он может выдавать список экземпляров, например, если вы получаете экземпляр Bean по типу, вы можете получить список экземпляров Bean.
Иерархическая фабрика компонентов:
В основном для достижения многослойности фабрики Bean.
AutowireCapableBeanFactory:
Фабрика бобов Autowired
Этот фабричный интерфейс наследуется от BeanFacotory, который расширяет функцию автоматической сборки, собирает бины в соответствии с определением класса BeanDefinition, выполняет пре- и постпроцессоры и т.д.
ConfigurableBeanFactory
Компонентная фабрика сложной конфигурации
ConfigurableListableBeanFactory
Этот класс очень большой, всего в интерфейсе фабрики 83 интерфейса, включая все текущие методы системы BeanFactory.
BeanDefinitionRegistry
Используется для управления объектами BeanDefinition, определенными внутри фабрики. Например, зарегистрируйте BeanDefinition, чтобы получить BeanDefinition.
Система наследования BeanDefinition
Система наследования ApplicationContext
Источник разрешает статьи
Создайте IOC-контейнер
После знакомства с основным интерфейсом мы входим в анализ исходного кода
Запись анализа: AbstractApplication#refresh()
Весь процесс инициализации контейнера можно условно разделить на шаги 12. Читатели, которым интересно, какой шаг может решить использовать его в качестве входа ветки, чтобы понять его принцип. Здесь я анализирую шаги 2 и 11, которые являются наиболее важными процессами IOC: процесс создания BeanFactory и процесс инициализации Bean. Для экономии места соответствующие отвлекающие факторы, такие как блоки try/catch, опущены.
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 1: 刷新预处理
// 设置Spring容器的启动时间,撤销关闭状态,开启活跃状态。
// 初始化属性源信息(Property)
// 验证环境信息里一些必须存在的属性
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 2:
// a) 创建IOC容器(DefaultListableBeanFactory)
// b) 加载解析XML文件(最终存储到Document对象中)
// c) 读取Document对象,并完成BeanDefinition的加载和注册工作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 3: 对IOC容器做一些预处理(设置一些公共属性)
prepareBeanFactory(beanFactory);
// 4:
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 5:调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 6: 注册BeanPostProcessor后置处理器
registerBeanPostProcessors(beanFactory);
// 7: 初始化一些消息源(比如处理国际化的i18n等消息资源)
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
// 8: 初始化应用事件广播器
initApplicationEventMulticaster();
// 9:初始化一些特殊的bean
// Initialize other special beans in specific context subclasses.
onRefresh();
// 10:注册一些监听器
// Check for listener beans and register them.
registerListeners();
// 11:实例化剩余的单例bean(非懒加载方式)
// 注意事项: Bean的IOC、ID和AOP都是发生在此步骤
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 12: 完成刷新时,需要发布对应的事件
// Last step: publish corresponding event.
finishRefresh();
}
//...省略try/catch代码块
Мы следуем шагу 2 getFreshBeanFactory(), который в основном завершает синтаксический анализ XML-файла (в конечном итоге сохраненного в объекте Document), считывает объект Document, завершает загрузку и регистрацию BeanDefinition и возвращает фабрику Bean DefaultListableBeanFactory, читатели могут сравните Глядя на приведенную выше диаграмму классов UML, найдите расположение DefaultListableBeanFactory и ощутите роль этого класса.
Затем мы переходим к AbstractRefreshableApplicationContext#refreshBeanFactory.
Здесь мы создадим более важную контейнерную фабрику контейнеров IOC, DefaultListableBeanFactory, информация нашего файла конфигурации хранится здесь в виде объектов BeanDefinition, мы обращаем внимание на loadBeanDefinitions(beanFactory); эта строка кода, здесь для загрузки нашей конфигурации файл и инкапсулировать его в BeanDefinition. Здесь сосуществует логическая реализация DefaultListableBeanFactory, здесь определен только метод ловушки, а реализация в основном реализуется подклассами, что немного похоже на метод абстрактного шаблона в шаблоне проектирования.
protected final void refreshBeanFactory() throws BeansException {
// 如果之前有IOC容器,则销毁
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
// 创建IOC容器,也就是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
customizeBeanFactory(beanFactory);
// 调用BeanDefinition的方法,在当前类中定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器。
loadBeanDefinitions(beanFactory); // 钩子方法
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
//...省略try/catch代码块
}
Здесь нас в основном интересует класс реализации, соответствующий конфигурационному файлу xml, а также в виде аннотаций.Заинтересованные читатели могут использовать это как ветку для углубленного исследования.
Мы переходим к AbstractXmlApplicationContext#loadBeanDefinitions
Здесь мы увидели принцип проектирования изоляции интерфейсов и принцип единой ответственности и изначально осознали преимущества определения такого количества интерфейсов. Давайте сначала посмотрим на систему наследования BeanFactory.DefaultListableBeanFactory реализует интерфейс BeanDefinitionRegistry и имеет возможность регистрировать BeanDefinition, но то, что здесь передается XmlBeanDefinitionReader, считывателю BeanDefinition, проходит только в BeanDefinitionRegistry, который имеет функциональный интерфейс регистрации BeanDefinition (мы см. структуру XmlBeanDefinitionReader Функция знает общедоступный XmlBeanDefinitionReader (реестр BeanDefinitionRegistry)), другие возможности все еще находятся в DefaultListableBeanFactory, который фактически защищает DefaultListableBeanFactory, отражая эффект изоляции интерфейса.
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 创建一个BeanDefinition阅读器,通过阅读XML文件,真正完成BeanDefinition的加载和注册
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
// 委托给BeanDefinitions阅读器去加载BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}
Затем мы вводим метод loadBeanDefinitions,
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 获取资源的定位
// 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
// 比如:ClassPathXmlApplicationContext中进行了实现
// 而FileSystemXmlApplicationContext没有使用该方法
Resource[] configResources = getConfigResources();
if (configResources != null) {
// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
reader.loadBeanDefinitions(configResources);
}
// 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
reader.loadBeanDefinitions(configLocations);
}
}
Здесь мы в основном рассматриваем
reader.loadBeanDefinitions(configLocations) и введите
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 获取在IOC容器初始化过程中设置的资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
// ...省略try/catch代码块
}
Входим в его подкласс XmlBeanDefinitionReader#loadBeanDefinitions
Здесь поток InputStream XML-файла будет получен и инкапсулирован в InputSource.Мы в основном рассматриваем конкретный процесс синтаксического анализа doLoadBeanDefinitions.
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//...省略若干代码
// 将资源文件转为InputStream的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
// 从InputStream中得到XML的解析流
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 具体的解析过程
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
//...省略try/catch代码块
}
Приходим к XmlBeanDefinitionReader#doLoadBeanDefinitions:
Здесь в основном нужно инкапсулировать XML в объект Document, а затем проанализировать объект Document, чтобы завершить загрузку и регистрацию BeanDefinition. После неисчислимых лишений, мы наконец пришли к этому шагу, это не просто!
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
// 通过DOM4加载解析XML文件,最终形成Document对象
Document doc = doLoadDocument(inputSource, resource);
// 通过对Document对象的解析操作,完成BeanDefinition的加载和注册工作
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
// .../省略try/catch代码块
Давайте посмотрим, как регистрируется BeanDefinition.
Перейти к XmlBeanDefinitionReader#registerBeanDefinitions
Это хорошо использует принцип единой ответственности в объектно-ориентированном подходе и делегирует логическую обработку одному классу для обработки, например: BeanDefinitionDocumentReader
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 记录统计前BeanDefinition的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
// 加载及注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 记录本次加载的BeanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
Мы идем в BeanDefinitionDocumentReader#registerBeanDefinitions
И введите в его класс реализации по умолчанию DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
// 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//...省略掉了默认命名空间的代码
// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
preProcessXml(root); // 钩子方法
// 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
parseBeanDefinitions(root, this.delegate);
// 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
postProcessXml(root); // 钩子方法
this.delegate = parent;
}
Здесь нас в основном интересуют определения parseBeanDefinitions.
Перейти к DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
Это более важно, пройти и проанализировать все дочерние узлы объекта Document, здесь нас интересует только parseDefaultElement, то есть теги компонентов, теги импорта, теги псевдонимов, а затем использовать правила разбора по умолчанию.
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
if (delegate.isDefaultNamespace(root)) {
// 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
// bean标签、import标签、alias标签,则使用默认解析规则
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else { //像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
Мы идем к DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析<import>标签
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 解析<alias>标签
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 解析bean标签
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
// 递归调用
doRegisterBeanDefinitions(ele);
}
}
Здесь мы в основном смотрим на разбор тегов, другие читатели могут сами прочитать, если им интересно.
Мы переходим к DefaultBeanDefinitionDocumentReader#processBeanDefinition
BeanDefinitionParserDelegate#parseBeanDefinitionElement будет анализировать BeanDefinition и инкапсулировать его в BeanDefinitionHolder,
BeanDefinitionReaderUtils#registerBeanDefinition окончательно зарегистрирует BeanDefinition в BeanDefinitionRegistry (DefaultListableBeanFactory) и сохранит его в карте: private final Map
Заинтересованные читатели могут продолжать следить за нами, здесь мы, наконец, разобрали BeanDefinition. Завершен шаг 2 AbstractApplicationContext#refresh(): анализ XML-файла и работа по загрузке и регистрации BeanDefinition.
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析<bean>标签,获取BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
создавать экземпляры бобов
Давайте взглянем на шаг 11 AbstractApplicationContext#refresh(), который важен, важен, важен. . .
Создание экземпляра singleton bean-компонента здесь завершено, и на этом этапе выполняются IOC, ID и AOP bean-компонента.
AbstractApplicationContext#finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//... 省略掉了若干代码
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化单例bean
beanFactory.preInstantiateSingletons();
}
Мы идем в DefaultListableBeanFactory#preInstantiateSingletons
Давайте сначала поймем разницу между BeanFactory и FactoryBean,
-
BeanFactory — это интерфейс верхнего уровня Spring и базовый контейнер Spring, отвечающий за управление экземплярами bean-компонентов.
-
FactoryBean — это просто объект bean, управляемый в контейнере spring, это просто означает, что способность этого bean-компонента — генерировать другой объект.
-
BeanFactory — это большая фабрика, включающая в себя все
-
FactoryBean — это небольшая фабрика, которая может производить только определенные объекты, и эта маленькая фабрика также управляется большой фабрикой.
-
FactoryBean и обычные экземпляры Bean также обрабатываются по-разному при управлении Spring. Отличить FactoryBean от обычного экземпляра Bean по префиксу &
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 触发所有非懒加载方式的单例bean的创建
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果bean是一个FactoryBean,则走下面的方法
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else { // 普通bean走下面的方法
getBean(beanName);
}
}
}
//...省略掉若干代码
}
Здесь мы идем с обычным Бином
Введите AbstractBeanFactory#getBean,
и перейдите в AbstractBeanFactory#doGetBean
Этот метод в основном делится на два этапа:
- Получите singleton bean-компонент из кеша и определите, получен ли он.Если полученный bean-компонент является FactoryBean, вам необходимо сгенерировать объект из экземпляра FactoryBean.
- Если Бин не получен, вам необходимо создать экземпляр Бин через BeanDefinition для возврата
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 获取bean的名称
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 从缓存中获取单例bean
Object sharedInstance = getSingleton(beanName);
// 如果获取到单例bean,则走下面代码
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else { // 如果没有获取到单例bean,则走下面代码
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 如果原型模式的Bean发生循环引用,则直接不处理,直接抛异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//...省略了检测BeanDefinition是否在Factory中的代码
try {
// 获取实例化的bean的BeanDefinition对象
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查该BeanDefinition对象对应的Bean是否是抽象的
checkMergedBeanDefinition(mbd, beanName, args);
//...省略检测代码
// Create bean instance.
// 如果是单例的Bean,看下面代码
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建单例Bean的主要方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) { // 原型
//...省略了处理原型模式Bean的分支
}
else {
//...省略了比如处理request、session级别的bean的分支
}
return (T) bean;
}
Мы в основном смотрим на этот код (важно):
Здесь используются лямбда-выражения Java 8
// Create bean instance.
// 如果是单例的Bean,看下面代码
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建单例Bean的主要方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
Перейти к DefaultSingletonBeanRegistry#getSingleton
Здесь рассматривается проблема циклических зависимостей, что такое циклическая зависимость и как Spring решает циклические зависимости, с нетерпением жду моей следующей статьи.
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...省略检测代码
// 创建之前,设置一个创建中的标识
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 调用匿名内部类获取单例对象
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
//...省略catch代码块
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 消除对象创建中的标识
afterSingletonCreation(beanName);
}
// 将产生的单例Bean放入缓存中(总共三级缓存)
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
Вышеприведенный singletonObject = singletonFactory.getObject(); вызывает метод createBean(beanName, mbd, args) в лямбда-выражении.
Входим в его класс реализации
AbstractAutowireCapableBeanFactory#createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//...省略若干代码块
// 完成Bean实例的创建(实例化、填充属性、初始化)
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
в то, что нас волнует
AbstractAutowireCapableBeanFactory#doCreateBean
На этом создание экземпляра Bean завершено, включая три шага:
-
создавать экземпляр
По умолчанию вызывается bean-компонент создания экземпляра построения без параметров, и на этом этапе происходит внедрение зависимостей параметров построения.
-
Население свойств (на этом этапе происходит внедрение зависимостей DI)
Установка атрибутов с использованием техник рефлексии и самоанализа
-
Инициализация (на этом этапе происходит АОП)
Он также использует отражение для вызова методов инициализации, таких как
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// bean初始化第一步:默认调用无参构造实例化Bean
// 构造参数依赖注入,就是发生在这一步
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 实例化后的Bean对象
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//...省略若干代码
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 解决循环依赖的关键步骤
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
// 如果需要提前暴露单例Bean,则将该Bean放入三级缓存中
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 将刚创建的bean放入三级缓存中singleFactories(key是beanName,value是FactoryBean)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// bean初始化第二步: 填充属性(DI依赖注入发生在此步骤)
// 这里主要分为两种情况:
// 1.对于非集合类型的属性,直接使用反射和内省机制去进行属性设置
// 2。对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性
populateBean(beanName, mbd, instanceWrapper);
// bean初始化第三步:调用初始化方法,完成bean的初始化操作(AOP发生在此步骤)
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
//... 省略catch块代码
//...省略若干代码
return exposedObject;
}
На этом этапе контейнер SpringIOC завершил загрузку, синтаксический анализ и внедрение зависимостей файлов ресурсов, определенных bean-компонентом.Теперь контейнер SpringIOC управляет серией bean-компонентов, связанных зависимостями.Программе не нужно вручную создавать требуемые объекты сами по себе. SpringIOC Контейнер автоматически создаст его для нас, когда мы его используем, и введет для нас соответствующие зависимости. Это связанная функция основной функции Spring по инверсии управления и внедрению зависимостей. Так называемая инверсия предназначена для передать право на создание бина.Управление пружиной.