Spring源码全解
文章目录1.容器简介什么是容器?IOC/DI2.容器的结构2.1 BeanFactory2.2 ApplicationContext2.2.1 ConfigurableApplicationContext2.2.2 WebApplicationContext3、ApplicationContext 启动流程3.1、prepareRefresh3.2、obtainFreshBeanFactory1.
1.容器简介
什么是容器?
Java应用中,对象与对象之间往往存在各种复杂的依赖,对象的构建也会变得越来越复杂,如果这些对象的生命周期全部由开发人员编写的话,那么工作量将会变得无比巨大,对象的管理也会非常复杂。所以才会诞生容器的概念,容器的核心左右只有一个:Bean的管理,当我们需要使用某个 Bean 时,容器会自动帮我们创建,并在适当时销毁。外界有一个标准的名词,前者称呼为 IOC,也就是控制反转,后者称呼为 DI,也就是依赖注入。
IOC/DI
-
IOC (Inversion of Control) 控制反转:
所谓控制反转,就是当我们需要某个 Bean 时,将 Bean 的名称告知容器,由容器去创建该 Bean,而不是我们手动 new 一个,这里 Bean 创建管理的控制权都交给了容器,所以这是一种控制权的反转。其通俗点讲就是需要什么东西让别人送过来,而不是自己去拿。
-
DI (Dependency Injection) 依赖注入:
就是指当 A 里面需创建 B 时,会在创建 A的时候,自动将依赖的 B 注入进去,其 B 是被动接受注入而不是自己主动去找。换句话说就是指 A 不是从容器中查找它依赖的 B ,而是容器创建在A 的时候主动将它依赖的 B 注入给它。
2.容器的结构
容器本质上是依赖于 Bean 工厂,该工厂管理 Bean 的生命周期,以及 Bean 之间的依赖关系。外界也将 Spring 容器称为 IOC 容器。当然,这里容器仅仅是 Spring 的抽象概念,代码中将其具象化为 BeanFactory 或 ApplicationContext,容器功能也由具象化的类进行处理。
2.1 BeanFactory
BeanFactory 是容器最基础的类,它定义了容器的基本功能规范:
public interface BeanFactory {
// 对 FactoryBean 的转义定义,因为如果使用 bean 的名字检索 FactoryBean 得到的对象是工厂生成的对象,
String FACTORY_BEAN_PREFIX = "&";
// 根据 bean 的名字,获取在容器中 bean 实例
Object getBean(String name) throws BeansException;
//根据 bean 的名字和 Class 类型来得到 bean 实例,增加了类型安全验证机制。
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 提供对 bean 的检索,看看是否在容器有这个名字的 bean
boolean containsBean(String name);
// 根据 bean 名字,判断这个 bean 是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 根据 bean 名字,判断这个 bean 是不是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 根据 bean 名字,判断是否与指定的类型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
// 得到 bean 实例的 Class 类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 得到bean 的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);
}
在 BeanFactory 里只对容器的基本行为作了定义,其根本不关心你的 Bean 是如何定义怎样加载的。至于工厂是怎么生产这些对象的,这个基本的接口不关心。而要知道工厂是如何产生对象的,我们就需要看具体的容器了,也就是 BeanFactory 的子类。
BeanFactory 大致的继承关系如下:
BeanFactory
体系中常用的实现类有:
ListableBeanFactory
:提供容器中 bean 迭代的功能。如返回所有 Bean 的名字、容器中 Bean 的数量等。HierarchicalBeanFactory
:提供父容器的访问功能,可通过ConfigurableBeanFactory
的setParentBeanFactory
方法设置父容器。AutowireCapableBeanFactory
:为 Spring 容器之外的 Bean ,也就是未交由 Spring 管理的 Bean ,提供依赖注入的功能。
以上三个是 BeanFactory
的直系亲属,这个三个直系亲属下面又派生了两个复杂的容器:
ConfigurableBeanFactory
:其继承了 HierarchicalBeanFactory 和SingletonBeanRegistry 这两个接口,其提供了很多方法,如:定义类加载器、类型转化、属性编辑器、注册依赖 Bean、销毁 bean 等,且该接口被大多数的容器继承、实现。ConfigurableListableBeanFactory
:这个接口继承了ListableBeanFactory
、AutowireCapableBeanFactory
、ConfigurableBeanFactory
,自身主要提供用于分析和修改bean
定义以及预先实例化单例 Bean 的方法。 最后是核心容器:
DefaultListableBeanFactory
:它实现了以上所有的接口,在 BeanFactory
体系中可以作为一个独立的容器使用。
2.2 ApplicationContext
上面说过 ApplicationContext 是 BeanFactory 子类,它实现了 BeanFactory 所有接口,但是本质还是通过BeanFactory来实现bean的操作的,还对其进行了扩展,而我们喜欢将 ApplicationContext 称为应用上下文,因为容器只是它的基本功能。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// 返回此应用程序上下文的唯一ID
@Nullable
String getId();
// 返回此上下文所属的应用程序名称
String getApplicationName();
// 返回应用上下文具像化的类名
String getDisplayName();
// 返回第一次加载此上下文时的时间戳
long getStartupDate();
// 获取父级应用上下文
@Nullable
ApplicationContext getParent();
// 将 AutowireCapableBeanFactory 接口暴露给外部使用
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
ApplicationContext
自身提供的方法非常简单,但它继承了六个接口,来扩展自身功能:
EnvironmentCapable
:获取 Environment。ListableBeanFactory
、HierarchicalBeanFactory
:这是BeanFactory
体系接口,分别提供 Bean 迭代和访问父容器的功能。MessageSource
:支持国际化功能。ApplicationEventPublisher
:应用事件发布器,封装事件发布功能的接口。ResourcePatternResolver
:该接口继承至 ResourceLoader ,作用是加载多个 Resource。ApplicationContext
同样提供了非常多的实现类,其又可细分为两大类,ConfigurableApplicationContext
和WebApplicationContext
。
2.2.1 ConfigurableApplicationContext
该接口是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在ApplicationContext
的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 应用上下文配置时,这些符号用于分割多个配置路径
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
// BeanFactory中,ConversionService类所对应的bean的名字。如果没有此类的实例的话吗,则使用默认的转换规则
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
//LoadTimeWaver类所对应的Bean在容器中的名字。如果提供了该实例,上下文会使用临时的 ClassLoader ,这样,LoadTimeWaver就可以使用bean确切的类型了
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
// Environment 类在容器中实例的名字
String ENVIRONMENT_BEAN_NAME = "environment";
// System 系统变量在容器中对应的Bean的名字
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
// System 环境变量在容器中对应的Bean的名字
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
// 设置容器的唯一ID
void setId(String id);
// 设置此容器的父容器
void setParent(@Nullable ApplicationContext parent);
// 设置容器的 Environment 变量
void setEnvironment(ConfigurableEnvironment environment);
// 以 ConfigurableEnvironment 的形式返回此容器的环境变量。以使用户更好的进行配置
@Override
ConfigurableEnvironment getEnvironment();
// 此方法一般在读取应用上下文配置的时候调用,用以向此容器中增加BeanFactoryPostProcessor。增加的Processor会在容器refresh的时候使用。
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 向容器增加一个 ApplicationListener,增加的 Listener 用于发布上下文事件,如 refresh 和 shutdown 等
void addApplicationListener(ApplicationListener<?> listener);
// 向容器中注入给定的 Protocol resolver
void addProtocolResolver(ProtocolResolver resolver);
// 这是初始化方法,因此如果调用此方法失败的情况下,要将其已经创建的 Bean 销毁。
// 换句话说,调用此方法以后,要么所有的Bean都实例化好了,要么就一个都没有实例化
void refresh() throws BeansException, IllegalStateException;
// 向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文
void registerShutdownHook();
// 关闭此应用上下文,释放其所占有的所有资源和锁。并销毁其所有创建好的 singleton Beans
@Override
void close();
// 检测此 FactoryBean 是否被启动过
boolean isActive();
// 返回此应用上下文的容器。
// 千万不要使用此方法来对 BeanFactory 生成的 Bean 做后置处理,因为单例 Bean 在此之前已经生成。
// 这种情况下应该使用 BeanFactoryPostProcessor 来在 Bean 生成之前对其进行处理
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
该接口下又有几个重要的实现类:
- AbstractApplicationContext:这是个抽象类,仅实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。
- GenericApplicationContext:该类继承自 AbstractApplicationContext,是为通用目的设计的,它能加载各种配置文件,例如 xml,properties 等等。它的内部持有一个 DefaultListableBeanFactory 的实例,实现了
- BeanDefinitionRegistry 接口,以便允许向其应用任何 bean 的定义的读取器。
- AnnotationConfigApplicationContext:该类继承自 GenericApplicationContext,提供了注解配置(例如:@Configuration、@Component等)和类路径扫描(scan方法)的支持。
2.2.2 WebApplicationContext
该接口是专门为 Web 应用准备的,其允许从相对于 Web 根目录的路径中装载配置文件完成初始化。
public interface WebApplicationContext extends ApplicationContext {
// 整个 Web 应用上下文是作为属性放置在 ServletContext 中的,该常量就是应用上下文在 ServletContext 属性列表中的 key
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
// 定义了三个作用域的名称
String SCOPE_REQUEST = "request";
String SCOPE_SESSION = "session";
String SCOPE_APPLICATION = "application";
// 在工厂中的 bean 名称
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
// ServletContext 初始化参数名称
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
// 在工厂中 ServletContext 属性值环境bean的名称
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
// 用来获取 ServletContext 对象
@Nullable
ServletContext getServletContext();
}
该接口的核心实现类有:
ConfigurableWebApplicationContext
:该接口同时继承了WebApplicationContext
和ConfigurableApplicationContext
,提供了 Web 应用上下文的可配置的能力。GenericWebApplicationContext
:该类继承自GenericApplicationContext
,实现了
ConfigurableWebApplicationContext
。XmlWebApplicationContext
:该上下文是使用 Xml 配置文件的方式,不过是在 Web 环境中使用的。AnnotationConfigServletWebServerApplicationContext
:该类是被SpringBoot
扩展而来的,SpringBoot 使用的就是该上下文。
3、ApplicationContext 启动流程
从启动类开始
@Xiao7Application(appName = "example", port = "8081", env = AppConstant.ENV_DEV)
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
SpringApplicatio在创建的时候会初始化一些初期化器、监听器等,就是使用SpringFactoriesLoader加载项目下的META-INF/spring,factories文件下的配置类。比如:
SpringApplication的run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 1、获取启动监听器,只有一个。
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 2、准备环境,就是通过事件监听器加载配置文件信息。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 3、准备容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
// 4、刷新容器
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);
}
try {
// 容器运行事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
-
1、prepareEnvironment:这一步会创建一个
StandardServletEnvironment
,然后发布一个ApplicationEnvironmentPreparedEvent
环境准备的事件,交给监听器去设置环境变量,主要涉及的是两个类:ConfigFileApplicationListener
(配置文件的监听器)、EnvironmentPostProcessor
(环境配置的后置处理器,其实就是在监听里面去进一步扩展了配置环境的加载)。
-
2、prepareContext:这一步会执行ApplicationContextInitializer初始化接口,发布ApplicationContextInitializedEvent容器初始化事件、初始化完就发布ApplicationPreparedEvent容器准备事件等。
-
3、AbstractApplicationContext的refresh方法,刷新容器前会先注册一个shutdownHook调用application.close(),在jvm关闭时调用close()关闭容器。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 初始化 refresh 的上下文环境,就是记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
prepareRefresh();
// 2. 初始化 BeanFactory,加载并解析配置,会添加一些必要的Processor
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 3. 对 BeanFactory 进行功能增强,如设置BeanFactory的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 4. 后置处理 beanFactory,交由子类实现
postProcessBeanFactory(beanFactory);
// 5. 调用已注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor,仅仅是注册,调用在getBean的时候。
// 6.1、同时添加了一个ApplicationListenerDetector
registerBeanPostProcessors(beanFactory);
// 7. 初始化国际化资源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 留给子类实现的模板方法
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 实例化所有非延迟加载的单例
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新过程,发布应用事件
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
// 13.销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
this.destroyBeans();
// Reset 'active' flag.
this.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...
this.resetCommonCaches();
}
}
}
逐一分析:
3.1、prepareRefresh
初始化 refresh 的上下文环境,就是记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
3.2、obtainFreshBeanFactory
如果父类是AbstractRefreshableApplicationContext这个的话,会消费已有的beanFactory重新创建一个,并进行初步的初始化,这里还会有一步加载的操作:loadBeanDefinitions(beanFactory)
。
主要有两步操作:
- 使用
ClassPathBeanDefinitionScanner
去扫描指定包中的Bean,默认创建的Scanner
只会注册Component
、ManagedBean
、Named
这三种注解的Bean - 如果
includeAnnotationConfig
属性为true
的话会注册一些支持注解、事件的处理器,比如:ConfigurationClassPostProcessor
、AutowiredAnnotationBeanPostProcessor
、EventListenerMethodProcessor
、DefaultEventListenerFactory
等。
是AnnotationConfigServletWebApplicationContext
的话,父类在其实创建容器的时候默认构造就以及创建了。这里创建的时候需要的一些后置处理器其实也已经注入进来了的。如图:
3.3、prepareBeanFactory
对 BeanFactory
进行功能增强,如设置BeanFactory
的类加载器,添加几个 BeanPostProcessor
,比如:ApplicationContextAwareProcessor,aware接口的后置处理器等。
3.4、prepareBeanFactory
一个钩子方法,提供给子类扩展。
3.5、invokeBeanFactoryPostProcessors
调用已注册的 BeanFactoryPostProcessor
、BeanDefinitionRegistryPostProcessor
,其中BeanDefinitionRegistryPostProcessor
继承了BeanFactoryPostProcessor
接口。
这里会先执行BeanDefinitionRegistryPostProcessor
,然后在执行BeanFactoryPostProcessor
。并且会根据PriorityOrdered
、Ordered
优先级进行排序控制执行顺序。
两个接口的区别:
BeanDefinitionRegistryPostProcessor
:使用BeanDefinitionRegistry
,可以进行Bean
的注册删除操作。
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
BeanFactoryPostProcessor
:使用ConfigurableListableBeanFactory
,可以进行Bean
的创建删除操作。
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
在前面阶段会创建几个内置的后置处理器比如:ConfigurationClassPostProcessor
、AutowiredAnnotationBeanPostProcessor
,这两个后置处理器。
ConfigurationClassPostProcessor
:解析@Configuration
、ImportSelector
、ImportBeanDefinitionRegistrar
、@Import
@PropertySource
、@ImportResource
等接口和注解。并将解析的Bean注册进容器中去。AutowiredAnnotationBeanPostProcessor
:实现了InstantiationAwareBeanPostProcessor
在对象填充属性的时候会解析@Autowired
注解并inject
填充至对象属性中。
3.6-3.8、 initMessageSource、initApplicationEventMulticaster、onRefresh
初始化国际化资源、初始化事件广播器、容器刷新的钩子函数。
3.9、registerListeners
注册事件监听器:就是从已注册的Bean
中找出实现ApplicationListener
接口的Bean
添加进ApplicationEventMulticaster
中,如果有earlyApplicationEvents
容器事件的话,进行时间的派发。
3.10、finishBeanFactoryInitialization
这一步应该是整个容器刷新最重要的一步了。创建还没实例化的非懒加载的Bean
。
这一步只是创建还没实例化的Bean
,并不是说所所有Bean
的创建都在这里。Bean的创建可以在Factory
创建好之后的任何地方实例化,前提是需要考虑好Bean之间的依赖。对象的创建都是交给DefaultListableBeanFactory工厂去创建的。
创建单例bean的部分源码:getSingleton获取到Bean之后就会放入一级缓存中,getObjectForBeanInstance会判断Bean的类型并决定返回Bean,如果是factoryBean会返回getObject对象,如果是&获取FactoryBean的话则直接返回。
createBean
方法部分源码: doCreateBean
之前会给Bean
一下提前创建的机会,通过InstantiationAwareBeanPostProcessor
接口的postProcessBeforeInstantiation
方法实现。
然后才是创建Bean的过程,AbstractAutowireCapableBeanFactory的doCreateBean方法源码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 1、创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 执行后置处理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
// 2、放入三级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 3、填充属性
populateBean(beanName, mbd, instanceWrapper);
// 4、初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
....略
return exposedObject;
}
-
createBeanInstance
:使用构造方法实例化对象时会回调determineCandidateConstructors
方法寻找构造函数创建对象。没有才会使用默认构造函数。这里的实现就是AutowiredAnnotationBeanPostProcessor
自动注入后置处理器了,它会处理@Autowired
、@Value
等注解。Spring也是推荐我们是构造函数来实现自动注入的。 -
创建完实例后会执行
MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition
后置处理。
-
这时候有一步操作是用于解决循环依赖的问题。放入一个
FactoryBean
到三级缓存中,到时候获取对象会执行SmartInstantiationAwareBeanPostProcessor
的getEarlyBeanReference
方法获取代理对象,从而实现对代理对象循环依赖的支持。这里如果只是循环依赖的话二级缓存也是足够的。
-
populateBean
填充属性,填充之前会调用InstantiationAwareBeanPostProcessor
的postProcessAfterInstantiation
后置处理。
这一步会获取对象的PropertyValues
属性值对象,会调用InstantiationAwareBeanPostProcessor
的postProcessProperties
对属性对象扩展处理。
找对对应的属性对象后会执行操作,applyPropertyValues
这里有一步操作是使用BeanDefinitionValueResolver
解析值,因为注入的属性可能是对象而不是基础类型。比如如果是RuntimeBeanReference
对象则会去容器中获取到。最后通过反射将对象的属性设置进去。 -
initializeBean
初始化对象,到了这一步,其实对象已经创建好了,只是进行一些额外的初始化操作。invokeAwareMethods
:设置aware
对象(BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
)执行
BeanPostProcessor
的postProcessBeforeInitialization
初始化前置处理方法。invokeInitMethods(beanName, wrappedBean, mbd)
:执行自定义的初始化方法,执行先如果实现了InitializingBean
的接口的话会先调用afterPropertiesSet
方法然后执行
postProcessAfterInitialization
后置处理器方法。像Aop
的代理对象也就是在这一步去创建的,也有可能是getEarlyBeanReference
方法中创建的。protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
最后如果
Bean
实现了DisposableBean
、AutoCloseable
或者有DestroyMethod
的话则会为其注册一个DisposableBean
在容器关闭的时候会执行。对象的创建到这里也已经完成了。
3.11、 finishRefresh
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
这里有一个LifecycleProcessor
(生命周期的后置处理器),可以通过实现SmartLifecycle、Lifecycle、Phased接口,并注册进容器,就可以在容器启动完成后,进行自定义的相关组件的启动与关闭了。
最后就是完成刷新过程,发布ContextRefreshedEvent事件。
4、Spring中的钩子接口
4.1、Aware 接口
Aware
从字面意思理解就是知道、感知的意思,是用来获取 Spring
内部对象的接口。Aware 自身是一个顶级接口,它有一系列子接口,在一个 Bean
中实现这些子接口并重写里面的 set
方法后,Spring
容器启动时,就会回调该 set
方法,而相应的对象会通过方法参数传递进去。
BeanFactoryAware
:获取 BeanFactory 对象,它是基础的容器接口。ApplicationContextAware
:获取Content
BeanNameAware
:获取Bean
的名称。EnvironmentAware
:获取Environment
对象,它表示整个的运行时环境,可以设置和获取配置属性。ApplicationEventPublisherAware
:获取ApplicationEventPublisher
对象,它是用来发布事件的。ResourceLoaderAware
:获取ResourceLoader
对象,它是获取资源的工具。
4.2、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
是 Bean
工厂的后置处理器,一般用来修改上下文中的 BeanDefinition
,修改 Bean
的属性值。
BeanDefinitionRegistryPostProcessor
是 BeanDefinitionRegistry
的后置处理器,一般用来扩展Bean
的注册。
4.3、@Import、ImportSelector、ImportBeanDefinitionRegistrar
ImportSelector
是一个较为重要的扩展接口,通过该接口可动态的返回需要被容器管理的类,不过一般用来返回外部的配置类。可在标注 @Configuration
注解的类中,通过 @Import
导入 ImportSelector
来使用。
ImportBeanDefinitionRegistrar
和 ImportSelector
类似,也是配合 @Import
使用,不过 ImportBeanDefinitionRegistrar
更为直接一点,它可以直接把 Bean
注册到容器中。
它们是在ConfigurationClassPostProcessor
中扩展实现的,也是Spring
启动是会自动注册的几个处理器之一。
3.4、InstantiationAwareBeanPostProcessor
它是BeanPostProcessor
的子接口。
调用时机:
- 对象创建前调一次,给机会提前创建。
postProcessBeforeInstantiation
- 填充属性前调用一次。
postProcessAfterInstantiation
- 填充属性时调一次。
postProcessProperties
3.5、SmartInstantiationAwareBeanPostProcessor
它是InstantiationAwareBeanPostProcessor
的子接口。
predictBeanType
:断言这个Bean
的所属类型。determineCandidateConstructors
:获取对象的构造方法getEarlyBeanReference
:提供代理扩展的,获取对象的早起引用对象。
3.6、MergedBeanDefinitionPostProcessor
它是BeanPostProcessor
的子接口。
postProcessMergedBeanDefinition
:它会在对象实例化但是没填充属性值之前回调一次。resetBeanDefinition
:removeBeanDefinition
时的回调通知方法做一些缓存数据的变更之类的。
5、AOP的原理分析
了解Aop前需要了解java中代理的方式有哪一些:
Java
代理博客:https://www.cnblogs.com/cenyu/p/6289209.html
5.1、基本概念
在Spring AOP
中,代理对象执行的过程通常被称为通知,而通知者由三部分组成:
-
Pointcut(切点)
:可以把它看成匹配器,就是用来匹配某个类的某个方法的。public interface Pointcut { // 类过滤器 ClassFilter getClassFilter(); // 方法的匹配器 MethodMatcher getMethodMatcher(); // 默认的切点,总是匹配 Pointcut TRUE = TruePointcut.INSTANCE; }
-
Advice(通知)
:具体的通知方法,常用的就是MethodInterceptor
(方法的拦截器)就是你要实现的切面执行的代码要放的地方。// MethodInterceptor 也是继承Advice 的 public interface MethodInterceptor extends Interceptor,Advice { // MethodInvocation就是具体的方法执行器,调用invocation.proceed()执行 Object invoke(MethodInvocation invocation) throws Throwable; }
-
Advisor(通知者)
:可以把它看成Advice(通知)
和Pointcut(切点)
的集成管理者。public class Xiao7Advisor implements PointcutAdvisor{ @Override public Pointcut getPointcut() { return new Xiao7Point(); } @Override public Advice getAdvice() { return new Xiao7Interceptor(); } @Override public boolean isPerInstance() { return true; } }
5.2、主要逻辑
主要的实现逻辑是在AbstractAutoProxyCreator
中,先看一下它的集成继承机构结构。
可以看到它本身是实现了SmartInstantiationAwareBeanPostProcessor
、BeanPostProcessor
、InstantiationAwareBeanPostProcessor
三个后置处理器的。
主要作用的实现接口有三个:
-
getEarlyBeanReference
:获取早期引用的,前面说Spring
创建对象的时候,会将ObjectFactory
放入缓存中,最终调用的时候也是执行到这一步的。@Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); }
-
postProcessBeforeInstantiation
:Bean
开始创建前如果设置了提前暴露,会进来这一步,如果返回了对象就不会走Spring
的逻辑创建对象了。@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } 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; }
-
postProcessAfterInitialization
:初始化对象后执行方法,Aop
的代理对象基本都是在这一步去创建的public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 具体的创建代理对象的位置 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
看一下wrapIfNecessary
的具体的逻辑
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 1、会判断是否支持(Advice、Pointcut、Advisor、AopInfrastructureBean)和跳过
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// getAdvicesAndAdvisorsForBean 是去获取这个Bean支持的对应的通知者
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 这一笔就是去创建代理对象了
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
其中getAdvicesAndAdvisorsForBean
的主要逻辑是从已注册的对象中找出Advisor
,并且进行一次匹配,需要注意的是只要类和某一个方法匹配成功了就属于合格的Advisor
了。
找到的Advisor
之后就是去创建代理对象了。先会创建一个ProxyFactory
(代理工厂),把代理需要的对象放进去,然后把对象的通知也放进去。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 包装一下,同时需要做一下适配扩展
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
从proxyFactory.getProxy(getProxyClassLoader())
追述下去会到DefaultAopProxyFactory
中创建代理。
最终会根据接口的有无,是否配置代理目标类等判断使用Jdk
代理还是cglib
代理,这里构造具体的代理工厂使用的AdvisedSupport
就是上一步包装了advisors
和目标类的proxyFactory
。
这里的话只看下jdk
代理的逻辑。JdkDynamicAopProxy
中的主要源码:
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取advised中的代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 创建代理对象,其中InvocationHandler就是当前对象,也就是JdkDynamicAopProxy
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy.invoke
的主要代码如下:
// 会先从advisors中获取到满足这个方法的advice也就是具体的每一个拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 为空的话走原逻辑
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 需要创建一个方法执行器,把代理对象、参数、目标类、拦截器链传进去,然后执行
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
ReflectiveMethodInvocation
中的proceed
执行流程
public Object proceed() throws Throwable {
// currentInterceptorIndex默认是-1,
// 当它等于interceptorsAndDynamicMethodMatchers.size() - 1的时候就说明已经执行完了。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 可以自定义一个动态方法匹配,一直到这一步才会判断之后需要过滤这个方法
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
// MethodInterceptor调用,执行完一个后又会回来这个方法,一直到执行整个链路都执行完了。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这里的interceptorsAndDynamicMethodMatchers
就是真正需要执行的拦截器链了。
- 如果
advice
实现了InterceptorAndDynamicMethodMatcher
接口的话,在这里还会做一下最终的匹配。过了才会执行它。 - 这里
MethodInterceptor,invoke(this)
会一直递归循环,一直到满足(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1)
的时候才会执行原对象的具体方法。
6、Spring中的循环依赖思想
对象的依赖主要分为三种情况
- 循环依赖主要分为这三种,自身依赖于自身、互相循环依赖、多组循环依赖。
- 但无论循环依赖的数量有多少,循环依赖的本质是一样的。就是你的完整创建依赖于我,而我的完整创建也依赖于你,但我们互相没法解耦,最终导致依赖创建失败。
- 所以需要
Spring
提供了除了构造函数注入和原型注入外的,setter
循环依赖注入 解决方案
在Spring
中,实际上使用一级缓存或者是二级缓存都是可以解决循环依赖的,只需要把代理对象提前创建,在填充属性前放入缓存就可以了。但是这样子做会造成特殊情况逻辑复杂、不易扩展,也很不优雅。
/** 一级缓存,存放的是完全体的对象 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存,提前暴漏对象,没有完全实例化的对象 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** 三级缓存,存放的是还没完全实例化的对象工厂对象 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
public Object getSingleton(String beanName) {
Object singletonObject = singletonObjects.get(beanName);
if (null == singletonObject) {
singletonObject = earlySingletonObjects.get(beanName);
// 判断二级缓存中是否有对象,这个对象就是代理对象,因为只有代理对象才会放到三级缓存中
if (null == singletonObject) {
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 把三级缓存中的代理对象中的真实对象获取出来,放入二级缓存中
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
获取对象的逻辑就是,一级一级获取,如果三级缓存有,调用getObject()
获取对象,然后放入二级缓存并且清除掉三级缓存。
在创建出对象后,会根据是否循环创建等状态判断,放入三级缓存中。getEarlyBeanReference
就是后置处理器的某个接口方法,在AOP
的代理创建器中也实现了这个接口。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 填充属性。
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
举个例子说明一下:
A 和 B 互相依赖,其中A是代理对象。
- 当A对象
new
出来后,没填充属性前会被放进三级缓存,然后填充属性的时候发现依赖B,B就开始创建。 - B在
new
出来后,也进去了三级缓存,然后填充属性发现依赖于A,去获取A的时候发现三级缓存中存在A,就调用了getObject()
创建了A的代理对象,就跑到二级缓存去了,然后设置A属性。B完全创建完,放入一级缓存并且返回给了A。 - 然后A获取到了完整的B设置了属性,然后继续完成实例化。
注意的是在第3步开始的时候,B已经完全实例化完了,但是B中的A属性是还没完全初始化完的A代理对象。要直到第3步完全跑完A这个对象再算完全实例化完成。
注意要点
Spring
的依赖注入可以实现各种循环依赖,但是通过构造器是没办法实现循环依赖的。
因为三级缓存依赖于实例化但没填充属性的对象,通过构造函数依赖是没办法拥有提前对象的。
所以在Spring
中使用构造函数注入需要注意避免循环依赖。
更多推荐
所有评论(0)