关于java:springboot源码解析管中窥豹系列之aware六

3次阅读

共计 6507 个字符,预计需要花费 17 分钟才能阅读完成。

一、前言

  • Springboot 源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
  • 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的 springboot 源码管中窥豹系列。

二、ApplicationContextAware

  • 假如咱们想应用某个 bean, 如果是在 @Component 类上面,间接用 @Autowired 援用就行了
  • 假如咱们想在某个静态方法外面用,就不能用下面的办法了
  • 你可能想用 new Bean() 的形式,new 一个,然而这个 bean 外面的 @Autowired 援用用不了
  • 如果有一个动态的全局 ApplicationContext 就好了,用 spring 的能力获取 bean: ApplicationContext.getBean(clazz)
  • ApplicationContextAware 就是这个用途
public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

public interface Aware {

}

咱们写一个实现类:


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtil.applicationContext = applicationContext;}

    private static ApplicationContext getApplicationContext() {return applicationContext;}

    public static <T> T getBean(Class<T> clazz){return getApplicationContext().getBean(clazz);
    }

}
  • 通过 setApplicationContext,把 applicationContext 赋值到本地动态变量
  • 通过 ApplicationContext 的 getBean 就能够在静态方法中应用任何 bean 的能力了

三、源码剖析

咱们进入 SpringApplication 的 run 办法:

public ConfigurableApplicationContext run(String... args) {

    ...

    try {
        
        ...

        refreshContext(context);
        
        ...
    }
    catch (Throwable ex) {...}

    ...

    return context;
}

咱们进入 refreshContext(context) 外部:

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();}

        catch (BeansException ex) {if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization -" +
                        "cancelling refresh attempt:" + ex);
            }

            destroyBeans();

            cancelRefresh(ex);

            throw ex;
        }

        finally {resetCommonCaches();
        }
    }
}

这个 refresh 是 spring 的外围办法,当前会屡次用到,内容太多,咱们这次只关注一个办法:

  • prepareBeanFactory(beanFactory);
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
        ...

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        ...
    }
}

咱们先看 prepareBeanFactory(beanFactory):

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

    ...

    // Configure the bean factory with context callbacks.
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    ...
    
}

咱们看一下这个 addBeanPostProcessor 办法


private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // Remove from old position, if any
    this.beanPostProcessors.remove(beanPostProcessor);
    // Track whether it is instantiation/destruction aware
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {this.hasInstantiationAwareBeanPostProcessors = true;}
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {this.hasDestructionAwareBeanPostProcessors = true;}
    // Add to end of list
    this.beanPostProcessors.add(beanPostProcessor);
}
  • 先 remove, 再 add
  • beanPostProcessors 是一个线程平安的 list: CopyOnWriteArrayList
  • 咱们往下看看 new ApplicationContextAwareProcessor(this),留神:this 是 ApplicationContext
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)){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 ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }

}
  • 构造方法,把 applicationContext 设到本地变量上
  • 实现接口的办法:postProcessBeforeInitialization,回调的时候会用,次要是校验权限
  • 最上面的 invokeAwareInterfaces 是个公有的外围回调办法,依据不同类型,有不同回调

咱们看到除了 ApplicationContextAware,还有其它的 aware, 总共 6 个

  • EnvironmentAware:环境变量
  • EmbeddedValueResolverAware:值解析器
  • ResourceLoaderAware:资源加载器
  • ApplicationEventPublisherAware:事件公布器
  • MessageSourceAware:信息处理器
  • ApplicationContextAware:spring 容器

比方咱们想用全局的环境变量,就有 EnvironmentAware,想用 spring 的事件就用 ApplicationEventPublisherAware,等等

  • 起源找到了,ApplicationContextAwareProcessor 什么时候执行的呢?
  • 这个比拟麻烦,咱们前面单开一节再具体的去看。

欢送关注微信公众号:丰极,更多技术学习分享。

正文完
 0