文章目录
- Pre
- org.springframework.context.support.ApplicationContextAwareProcessor
- 内部的7个扩展点
- 源码解析
- 扩展示例
Pre
Spring Boot - 扩展接口一览
org.springframework.context.support.ApplicationContextAwareProcessor
代码语言:javascript复制/*
* 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.support;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationStartupAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
/**
* {@link BeanPostProcessor} implementation that supplies the {@code ApplicationContext},
* {@link org.springframework.core.env.Environment Environment}, or
* {@link StringValueResolver} for the {@code ApplicationContext} to beans that
* implement the {@link EnvironmentAware}, {@link EmbeddedValueResolverAware},
* {@link ResourceLoaderAware}, {@link ApplicationEventPublisherAware},
* {@link MessageSourceAware}, and/or {@link ApplicationContextAware} interfaces.
*
* <p>Implemented interfaces are satisfied in the order in which they are
* mentioned above.
*
* <p>Application contexts will automatically register this with their
* underlying bean factory. Applications do not use this directly.
*
* @author Juergen Hoeller
* @author Costin Leau
* @author Chris Beams
* @since 10.10.2003
* @see org.springframework.context.EnvironmentAware
* @see org.springframework.context.EmbeddedValueResolverAware
* @see org.springframework.context.ResourceLoaderAware
* @see org.springframework.context.ApplicationEventPublisherAware
* @see org.springframework.context.MessageSourceAware
* @see org.springframework.context.ApplicationContextAware
* @see org.springframework.context.support.AbstractApplicationContext#refresh()
*/
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
bean instanceof ApplicationStartupAware)) {
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
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 ApplicationStartupAware) {
((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
ApplicationContextAwareProcessor
本身并没有扩展点,但是该类内部却有6个扩展点可供实现 ,这些类触发的时机在bean实例化之后,初始化之前.
内部的7个扩展点
5.3.2版本
代码语言:javascript复制 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 ApplicationStartupAware) {
((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
-
EnvironmentAware
:用于获取EnviromentAware的一个扩展类,这个变量非常有用, 可以获得系统内的所有参数。个人认为这个Aware没必要去扩展,因为spring内部都可以通过注入的方式来直接获得。 -
EmbeddedValueResolverAware
:用于获取StringValueResolver的一个扩展类, StringValueResolver用于获取基于String类型的properties的变量,一般都用@Value的方式去获取,如果实现了这个Aware接口,把StringValueResolver缓存起来,通过这个类去获取String类型的变量,效果是一样的。 -
ResourceLoaderAware
:用于获取ResourceLoader的一个扩展类,ResourceLoader可以用于获取classpath内所有的资源对象,可以扩展此类来拿到ResourceLoader对象。 -
ApplicationEventPublisherAware
:用于获取ApplicationEventPublisher的一个扩展类,ApplicationEventPublisher可以用来发布事件,结合ApplicationListener来共同使用。这个对象也可以通过spring注入的方式来获得。 -
MessageSourceAware
:用于获取MessageSource的一个扩展类,MessageSource主要用来做国际化。 -
ApplicationStartupAware
: 要开始收集定制的StartupStep,组件可以实现ApplicationStartupAware接口直接获得ApplicationStartup实例或者在注入点请求ApplicationStartup类型。 -
ApplicationContextAware
:用来获取ApplicationContext的一个扩展类, ApplicationContext应该是很多人非常熟悉的一个类了,就是spring上下文管理器,可以手动的获取任何在spring上下文注册的bean,我们经常扩展这个接口来缓存spring上下文,包装成静态方法。同时ApplicationContext也实现了BeanFactory,MessageSource,ApplicationEventPublisher等接口,也可以用来做相关接口的事情。
源码解析
代码语言:javascript复制org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
我们继续看下 invokeAwareInterfaces(bean);
可知ApplicationContextAwareProcessor关联了大部分Spring内置Aware接口,它们的执行顺序如下:
代码语言:javascript复制EnvironmentAware -> EmbeddedValueResolverAware -> ResourceLoaderAware -> ApplicationEventPublisherAware -> MessageSourceAware -> ApplicationStartupAware -> ApplicationContextAware
我们来看下调用栈
代码语言:javascript复制org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
org.springframework.beans.factory.support.AbstractBeanFactory#getBean
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
processor.postProcessBeforeInitialization(result, beanName);
org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
org.springframework.context.support.ApplicationContextAwareProcessor#invokeAwareInterfaces
扩展示例
代码语言:javascript复制 package com.artisan.bootspringextend.testextends;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.*;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
/**
* @author 小工匠
* @version 1.0
* @description: TODO
* @date 2022/12/4 11:02
* @mark: show me the code , change the world
*/
@Slf4j
@Component
public class ExtendInvokeAware implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware,
ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,ApplicationStartupAware, ApplicationContextAware, ImportAware,
LoadTimeWeaverAware {
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
log.info(" ------> BeanClassLoaderAware::setBeanClassLoader invoked");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info(" ------> BeanFactoryAware::setBeanFactory invoked");
}
@Override
public void setBeanName(String s) {
log.info(" ------> BeanNameAware::setBeanName invoked");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info(" ------> ApplicationContextAware::setApplicationContext invoked");
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
log.info(" ------> ApplicationEventPublisherAware::setApplicationEventPublisher invoked");
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
log.info(" ------> EmbeddedValueResolverAware::setEmbeddedValueResolver invoked");
}
@Override
public void setEnvironment(Environment environment) {
log.info(" ------> EnvironmentAware::setEnvironment invoked");
}
@Override
public void setMessageSource(MessageSource messageSource) {
log.info(" ------> MessageSourceAware::setMessageSource invoked");
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
log.info(" ------> ResourceLoaderAware::setResourceLoader invoked");
}
@Override
public void setApplicationStartup(ApplicationStartup applicationStartup) {
log.info(" ------> ApplicationStartup::setApplicationStartup invoked");
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
log.info(" ------> ImportAware::setImportMetadata invoked");
}
@Override
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
log.info(" ------> LoadTimeWeaverAware::setLoadTimeWeaver invoked");
}
}
输出结果
代码语言:javascript复制 . ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.2)
2022-12-04 19:14:25.103 INFO 12832 --- [ main] .b.t.ExtendApplicationContextInitializer : ExtendApplicationContextInitializer # initialize Called
2022-12-04 19:14:25.110 INFO 12832 --- [ main] c.a.b.BootSpringExtendApplication : Starting BootSpringExtendApplication using Java 1.8.0_261 on LAPTOP-JF3RBRRJ with PID 12832 (D:IdeaProjectsboot2boot-spring-extendtargetclasses started by artisan in D:IdeaProjectsboot2)
2022-12-04 19:14:25.111 INFO 12832 --- [ main] c.a.b.BootSpringExtendApplication : No active profile set, falling back to default profiles: default
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> BeanNameAware::setBeanName invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> BeanClassLoaderAware::setBeanClassLoader invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> BeanFactoryAware::setBeanFactory invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> EnvironmentAware::setEnvironment invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> EmbeddedValueResolverAware::setEmbeddedValueResolver invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> ResourceLoaderAware::setResourceLoader invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> ApplicationEventPublisherAware::setApplicationEventPublisher invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> MessageSourceAware::setMessageSource invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> ApplicationStartup::setApplicationStartup invoked
2022-12-04 19:14:25.444 INFO 12832 --- [ main] c.a.b.testextends.ExtendInvokeAware : ------> ApplicationContextAware::setApplicationContext invoked
2022-12-04 19:14:25.529 INFO 12832 --- [ main] c.a.b.BootSpringExtendApplication : Started BootSpringExtendApplication in 0.747 seconds (JVM running for 1.792)
Process finished with exit code 0