1. Введение
«Пожалуйста, опишите жизненный цикл Spring Bean?» Это распространенный вопрос интервьюеров, исследующих Spring, который показывает, что это очень важная точка знаний в Spring.
Когда я готовился к интервью, я искал ответы в Интернете, и большинство ответов были даны в процессе ниже.
Но когда я впервые увидел схему, у меня было сильное замешательство: «В курсе, BeanPostProcessor… что это такое? И там так много шагов, слишком много, как запомнить?».
На самом деле, мы должны помнить процесс, или мы должны сначала понять, эта статья поможет понять жизненный цикл бобов из следующих двух аспектов:
-
Резюме жизненного цикла: суммировать жизненный цикл компонентов и в сочетании с кодом;
-
Роль точек расширения: подробно опишите роль точек расширения, участвующих в жизненном цикле компонента.
2. Обзор процесса жизненного цикла
Жизненный цикл боба можно описать как4 этапа:
- Создание экземпляра
- Назначение свойства (заполнить)
- Инициализация
- Разрушение
-
Создать экземпляр: Шаг 1, создать экземпляр объекта bean;
-
Назначение свойства: Шаг 2, установите соответствующие свойства и зависимости для компонента;
-
Инициализация: шаги с 3 по 7, есть много шагов, среди которых шаги 5 и 6 являются операциями инициализации, шаги 3 и 4 выполняются до инициализации, а шаг 7 выполняется после инициализации.Пользователи могут использовать только после этого этапа;
-
Уничтожение: шаги с 8 по 10, 8-й шаг не является реальным уничтожением (еще не используется), но соответствующий интерфейс вызова для уничтожения регистрируется перед использованием, чтобы фактически уничтожить компонент на шагах 9 и 10. Выполнить соответствующий метод. .
Давайте посмотрим на код интуитивно, в методе doCreateBean() мы видим, что эти 4 этапа выполняются последовательно:
// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 实例化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object exposedObject = bean;
try {
// 2. 属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 4. 销毁-注册回调接口
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
Поскольку инициализация включает в себя шаги с 3 по 7, она более сложная, поэтому переходим к методу initializeBean(), чтобы увидеть процесс в деталях (порядковый номер аннотации соответствует порядковому номеру на рисунке):
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 3. 检查 Aware 相关接口并设置相关依赖
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 4. BeanPostProcessor 前置处理
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 5. 若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法
// 6. 若配置自定义的 init-method方法,则执行
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 7. BeanPostProceesor 后置处理
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
Интерфейс InitializingBean и метод init-method проверяются в методе invokInitMethods(), и процесс уничтожения аналогичен:
// DisposableBeanAdapter.java
public void destroy() {
// 9. 若实现 DisposableBean 接口,则执行 destory()方法
if (this.invokeDisposableBean) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
}
// 10. 若配置自定义的 detory-method 方法,则执行
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
Из исходного кода Spring мы можем интуитивно увидеть процесс его выполнения, и мы можем начать с этих четырех этапов, запомнив его процесс, создание экземпляра, назначение атрибутов, инициализацию и уничтожение. Наиболее подробной является инициализация, которая включает в себя понятия Aware, BeanPostProcessor, InitializingBean и init-метод. Это все точки расширения, предоставляемые Spring, и их конкретные роли будут описаны в следующем разделе.
3. Роль точек расширения
3.1 Осведомленный интерфейс
Если Spring обнаружит, что bean-компонент реализует интерфейс Aware, он внедрит для него соответствующие зависимости. такЗаставив компонент реализовать интерфейс Aware, соответствующие ресурсы контейнера Spring могут быть получены в компоненте..
Интерфейсы Aware, предоставляемые в Spring:
- BeanNameAware: внедрить текущий компонент, соответствующий beanName;
- BeanClassLoaderAware: внедряет ClassLoader, который загружает текущий компонент;
- BeanFactoryAware: вставляет ссылку на текущий контейнер BeanFactory.
Его кодовая реализация выглядит следующим образом:
// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
Вышеприведенное относится к контейнерам типа BeanFactory, а для контейнеров типа ApplicationContext также предоставляются интерфейсы Aware, но реализация внедрения этих интерфейсов Aware внедряется через BeanPostProcessor, но его роль по-прежнему заключается во внедрении зависимостей.
- EnvironmentAware: внедрение среды, обычно используемой для получения свойств конфигурации;
- EmbeddedValueResolverAware: внедрить EmbeddedValueResolver (парсер Spring EL), обычно используемый для разрешения параметров;
- ApplicationContextAware (ResourceLoader, ApplicationEventPublisherAware, MessageSourceAware): внедрить в сам контейнер ApplicationContext.
Его кодовая реализация выглядит следующим образом:
// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
3.2 BeanPostProcessor
BeanPostProcessor — это Springизменить бинПредоставляет мощную точку расширения, которая действует на все bean-компоненты в контейнере и определяется следующим образом:
public interface BeanPostProcessor {
// 初始化前置处理
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 初始化后置处理
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Общие сценарии:
- Для класса реализации интерфейса маркера выполните пользовательскую обработку. Например, ApplicationContextAwareProcessor, упомянутый в Разделе 3.1, внедрить для него соответствующие зависимости, например, пользовательский класс, реализующий интерфейс расшифровки, будет расшифровывать его атрибуты;
- Предоставляет реализацию прокси для текущего объекта. Например, функция Spring AOP, которая создает прокси-класс для объекта, а затем возвращает результат.
// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理类
return proxy;
}
return null;
}
3.3 InitializingBean и метод init
InitializingBean и init-method являются Spring дляинициализация бинапредусмотрены точки расширения.
Определение интерфейса InitializingBean выглядит следующим образом:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
Напишите логику инициализации в методе afterPropertiesSet().
Указываем метод init-method, указываем метод инициализации:
<?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">
<bean id="demo" class="com.chaycao.Demo" init-method="init()"/>
</beans>
DisposableBean и метод уничтожения аналогичны описанным выше и не будут описываться.
4. Резюме
Наконец, суммируйте, как запомнить жизненный цикл весеннего бона:
-
Первый - четыре основных этапа змеи, назначения атрибута, инициализации и уничтожения;
-
Далее идут специфические операции инициализации, включая внедрение зависимостей интерфейса Aware, обработку BeanPostProcessor до и после инициализации, а также операции инициализации InitializingBean и init-метода;
-
Конкретная операция уничтожения включает в себя регистрацию соответствующего интерфейса обратного вызова уничтожения и, наконец, его уничтожение с помощью DisposableBean и метода уничтожения.
5. Ссылка
- Пожалуйста, перестаньте спрашивать о жизненном цикле Spring Bean!
- Расскажите об этих механизмах растяжения пружины
Друзья, которым нравятся мои статьи, вы можете отсканировать код и подписаться на мой официальный аккаунт: "Травяной щипок"