实现方式
实现ApplicationContextAware类,重写setApplicationContext方法,并且添加@Component注解
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
if (Objects.isNull(SpringUtils.applicationContext)) {
SpringUtils.applicationContext = applicationContext;
}
}
public static String getProperty(String key) {
return applicationContext.getEnvironment().getProperty(key);
}
}
对静态变量进行赋值
public static String XXX = SpringUtils.getProperty("配置名");
⚠️ 如果获取配置时报空指针异常(applicationContext 还没有被初始化导致),在获取配置的类上面加入@DependsOn(“springUtils”) 即可
实现原理
1.Springboot项目启动的时候会执行main方法
SpringApplication.run(Application.class, args);
2.SpringApplication.run方法里面会调用AbstractApplicationContext.refresh()方法(这里涉及到springboot的启动流程)
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新容器准备环境
prepareRefresh();
// 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备Bean工厂
prepareBeanFactory(beanFactory);
try {
// 执行子类中的后置处理器:空方法
postProcessBeanFactory(beanFactory);
// 执行bean工厂的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean的后置处理器
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource
initMessageSource();
// 为此上下文初始化事件多播器。
initApplicationEventMulticaster();
// 让子类有点参与感,留给子类的初始化方法
onRefresh();
// 给容器中将所有项目里面的ApplicationListener注册进来
registerListeners();
// 最后初始化bean工厂,初始化所有剩下的单实例bean
finishBeanFactoryInitialization(beanFactory);
// 完成BeanFactory初始化创建工作
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
3.refresh()中的prepareBeanFactory()方法会设置ApplicationContextAwareProcessor(创建bean时会调用这个类的方法)
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
4.ApplicationContextAwareProcessor 中有个重写了的前置处理方法,如果创建的这个bean的类实现了ApplicationContextAware接口,那么就会调用该类setApplicationContext方法进行初始化
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 1.看下这里!!!
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
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);
}
// 2.看下这里!!!
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
5.配置文件的数据是在 SpringApplication.run 中调用 prepareEnvironment()方法通准备环境数据时加载的(在refresh()执行之前就加载好了)
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 在这里加载配置文件中的数据
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 在这里把配置文件的数据放到 applicationContext 中
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
6.初始化的处理逻辑有了,配置又有了,接下来就是触发初始化的逻辑了。
springboot启动流程中的这个方法:refresh() -> finishBeanFactoryInitialization(beanFactory) -> beanFactory.preInstantiateSingletons(),会通过getBean方法获取bean对象
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 看下这里!!!
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
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 {
// 看下这里!!!
getBean(beanName);
}
}
}
7.深入看下getBean() ->doGetBean()->createBean()->doCreateBean()->initializeBean()->applyBeanPostProcessorsBeforeInitialization()方法后,发现这里会遍历第3点设置的类,并执行第4点的前置处理方法
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
总结
Springboot项目启动时(第一点),会设置自动处理类,并把applicationContext放进去(第二、三点),自动处理类里面会有些已经实现好的功能(第四点),springboot读取到配置文件后会把配置放到applicationContext中(第五点),在springboot初始化bean工厂时(第六点),在getBean方法里面会调用到自动处理类的相关方法进行处理(第七点)。
所以实现 ApplicationContextAware 接口,并加上 @Component 注解,可以在获取 bean 的时候自动调用重写的 setApplicationContext 方法,拿到包含配置文件中的配置的 applicationContext,再从 applicationContext 中获取自己想要的配置。