BeanFactory
源码注释
/**
* The root interface for accessing a Spring bean container.
* 访问Spring bean容器的根接口。
* 什么是Spring bean容器?
* <p>This is the basic client view of a bean container;
* further interfaces such as {@link ListableBeanFactory} and
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
* are available for specific purposes.
* 这是bean容器的基础客户端视图,具体用途见ListableBeanFactory、ConfigurableBeanFactory接口
*
* <p>This interface is implemented by objects that hold a number of bean definitions,
* each uniquely identified by a String name. Depending on the bean definition,
* the factory will return either an independent instance of a contained object
* (the Prototype design pattern), or a single shared instance (a superior
* alternative to the Singleton design pattern, in which the instance is a
* singleton in the scope of the factory). Which type of instance will be returned
* depends on the bean factory configuration: the API is the same. Since Spring
* 2.0, further scopes are available depending on the concrete application
* context (e.g. "request" and "session" scopes in a web environment).
* 该接口被许多拥有一组bean definitions的对象实现,每个对象能通过一个字符串名称唯一识别。根据bean definition,
* 该工厂将会返回一个独立实例或共享实例。每种实例类型可以根据bean factory configuration返回,api都是相同的。
* 从spring2.0开始,实例返回可根据具体应用上下文获取
* 什么是bean definition?
* 什么是bean factory configuration,如何获取scope
*
* <p>The point of this approach is that the BeanFactory is a central registry
* of application components, and centralizes configuration of application
* components (no more do individual objects need to read properties files,
* for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and
* Development" for a discussion of the benefits of this approach.
* BeanFactory是应用组件的中心注册接口也是应用组件的中心配置接口
* bean是如何注册?
*
* <p>Note that it is generally better to rely on Dependency Injection
* ("push" configuration) to configure application objects through setters
* or constructors, rather than use any form of "pull" configuration like a
* BeanFactory lookup. Spring's Dependency Injection functionality is
* implemented using this BeanFactory interface and its subinterfaces.
* 依靠依赖注入通过setter和构造函数来配置应用对象的值,比使用pull方式的依赖查找更好。Spring的依赖注入功能
* 被BeanFactory接口和子接口实现
* 依赖注入与依赖查找如何使用依赖注入(DI)对应该的对象赋值
*
* <p>Normally a BeanFactory will load bean definitions stored in a configuration
* source (such as an XML document), and use the {@code org.springframework.beans}
* package to configure the beans. However, an implementation could simply return
* Java objects it creates as necessary directly in Java code. There are no
* constraints on how the definitions could be stored: LDAP, RDBMS, XML,
* properties file, etc. Implementations are encouraged to support references
* amongst beans (Dependency Injection).
* 通常BeanFactory会加载存储在配置资源中的bean定义,并使用org.springframework.beans包配置bean。然而,一个具体
* 的实现可以简单的返回创建的java对象,没有关于bean定义该如何存储的约束,比如:LDAP,RDBMS,XML,properties文件。
* 实现鼓励支持bean依赖注入
* 以上注释表明可自定义bean加载。如给出一种文件,将文件中的描述变为Bean Definition就能注册到容器中
*
* <p>In contrast to the methods in {@link ListableBeanFactory}, all of the
* operations in this interface will also check parent factories if this is a
* {@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,
* the immediate parent factory will be asked. Beans in this factory instance
* are supposed to override beans of the same name in any parent factory.
* 与ListableBeanFactory相比,HierarchicalBeanFactory接口中的所有操作都会检测父工厂。如果bean在当前工厂实例中
* 未找到,会立刻向父工厂查找。当前工厂实例中的bean应该覆盖父工厂中同名的bean
* <p>Bean factory implementations should support the standard bean lifecycle interfaces
* as far as possible. The full set of initialization methods and their standard order is:
* Bean工厂实现应该尽可能地满足标准的bean生命周期接口。初始化方法的全部步骤和标准顺序如下:
* <ol>
* <li>BeanNameAware's {@code setBeanName}
* <li>BeanClassLoaderAware's {@code setBeanClassLoader}
* <li>BeanFactoryAware's {@code setBeanFactory}
* <li>EnvironmentAware's {@code setEnvironment}
* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
* <li>ResourceLoaderAware's {@code setResourceLoader}
* (only applicable when running in an application context)
* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
* (only applicable when running in an application context)
* <li>MessageSourceAware's {@code setMessageSource}
* (only applicable when running in an application context)
* <li>ApplicationContextAware's {@code setApplicationContext}
* (only applicable when running in an application context)
* <li>ServletContextAware's {@code setServletContext}
* (only applicable when running in a web application context)
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
* <li>InitializingBean's {@code afterPropertiesSet}
* <li>a custom init-method definition
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
* </ol>
*
* <p>On shutdown of a bean factory, the following lifecycle methods apply:
* <ol>
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
* <li>DisposableBean's {@code destroy}
* <li>a custom destroy-method definition
* </ol>
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 13 April 2001
* @see BeanNameAware#setBeanName
* @see BeanClassLoaderAware#setBeanClassLoader
* @see BeanFactoryAware#setBeanFactory
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
* @see org.springframework.context.MessageSourceAware#setMessageSource
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
* @see org.springframework.web.context.ServletContextAware#setServletContext
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
* @see InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
* @see DisposableBean#destroy
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
*/
Spring Bean容器
Bean容器就是放对象的地方,使用如下Demo验证对象存放位置
@Service
public class UserA {
public void f1(){
System.out.println("userA f1...");
}
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(UserA.class);
UserA userA = annotationConfigApplicationContext.getBean(UserA.class);
userA.f1();
}
}
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
对象存放在DefaultSingletonBeanRegistry类的singletonObjects中。所以DefaultSingletonBeanRegistry为真正的Bean容器。类名直译:默认单例Bean登记处。
DefaultSingletonBeanRegistry的源码注释
/**
* Generic registry for shared bean instances, implementing the
* {@link org.springframework.beans.factory.config.SingletonBeanRegistry}.
* Allows for registering singleton instances that should be shared
* for all callers of the registry, to be obtained via bean name.
* 共享bean实例的通用登记处,实现了SingletonBeanRegistry,允许注册singleton实例,对于登记处的所有调用者实例是共享的,通过名字获
* 取
* <p>Also supports registration of
* {@link org.springframework.beans.factory.DisposableBean} instances,
* (which might or might not correspond to registered singletons),
* to be destroyed on shutdown of the registry. Dependencies between
* beans can be registered to enforce an appropriate shutdown order.
*
* <p>This class mainly serves as base class for
* {@link org.springframework.beans.factory.BeanFactory} implementations,
* factoring out the common management of singleton bean instances. Note that
* the {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
* interface extends the {@link SingletonBeanRegistry} interface.
* 该类主要是为BeanFactory的实现提供基础服务,提炼出单例bean实例的公共部分
* <p>Note that this class assumes neither a bean definition concept
* nor a specific creation process for bean instances, in contrast to
* {@link AbstractBeanFactory} and {@link DefaultListableBeanFactory}
* (which inherit from it). Can alternatively also be used as a nested
* helper to delegate to.
* 与AbstractBeanFactory、DefaultListableBeanFactory相反,该类既没有呈现bean definition的概念,也不承担bean实例的具体创建
* 流程
* @author Juergen Hoeller
* @since 2.0
* @see #registerSingleton
* @see #registerDisposableBean
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory
*/
从断点处getBean进入:
可以看到Bean是由BeanFactory获取的,正是注释中的第一句:The root interface for accessing a Spring bean container
继续debug可以看到此处的BeanFactory是DefaultListableBeanFactory
DefaultListableBeanFactory的UML图可简化一下:
DefaultListableBeanFactory源码注释
/**
* Spring's default implementation of the {@link ConfigurableListableBeanFactory}
* and {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
* based on bean definition metadata, extensible through post-processors.
* Spring中ConfigurableListableBeanFactory与BeanDefinitionRegistry(bean定义登记处)的默认实现。该类是基于bean定义元数据
* bean增强器扩展的全方位实现
* <p>Typical usage is registering all bean definitions first (possibly read
* from a bean definition file), before accessing beans. Bean lookup by name
* is therefore an inexpensive operation in a local bean definition table,
* operating on pre-resolved bean definition metadata objects.
* 在获取bean之前,先用于注册bean定义。在本地的bean定义表中通过名称查找bean是一个性能好高的操作
* <p>Note that readers for specific bean definition formats are typically
* implemented separately rather than as bean factory subclasses: see for example
* {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
*
* <p>For an alternative implementation of the
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
* have a look at {@link StaticListableBeanFactory}, which manages existing
* bean instances rather than creating new ones based on bean definitions.
*/
实现BeanFactory,继承DefaultSingletonBeanRegistry,使行为与容器分离。这里的妙处在于BeanFactory都不知道要操作什么容器,只提供了访问容器的行为,DefaultSingletonBeanRegistry实现简单对象存储,复杂的逻辑由具体的子类实现,比如Bean的创建过程,过程中的Aware通知,Bean的增强处理,Bean查找时的候选过滤,查找时校验等(上图让我想到《Head First 设计模式》入门篇中飞行和呱呱叫行为的抽象),DefaultListableBeanFactory是能真正获取到Bean的地方,然而代码中获取Bean的地方是由AnnotationConfigApplicationContext开始的,这里就引出了ApplicationContext
应用程序上下文
Demo中AnnotationConfigApplicationContext的UML图
ApplicationContext源码注释
/**
* Central interface to provide configuration for an application.
* This is read-only while the application is running, but may be
* reloaded if the implementation supports this.
*
* <p>An ApplicationContext provides:
* <ul>
* <li>Bean factory methods for accessing application components.
* Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.
* <li>The ability to load file resources in a generic fashion.
* Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.
* <li>The ability to publish events to registered listeners.
* Inherited from the {@link ApplicationEventPublisher} interface.
* <li>The ability to resolve messages, supporting internationalization.
* Inherited from the {@link MessageSource} interface.
* <li>Inheritance from a parent context. Definitions in a descendant context
* will always take priority. This means, for example, that a single parent
* context can be used by an entire web application, while each servlet has
* its own child context that is independent of that of any other servlet.
* </ul>
*
* <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory}
* lifecycle capabilities, ApplicationContext implementations detect and invoke
* {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware},
* {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans.
*/
框架简化UML
可以看到一个代理模式,上下文具有了访问Bean容器的所有能力,在AbstractApplicationContext可以看到
上下文具有访问BeanDefinition容器的所有能力,在GenericApplicationContext可以看到
BeanDefinition容器
在上面的UML图中,AnnotationConfigApplicationContext、DefaultListableBeanFactory都实现了BeanDefinitionRegistry接口:Bean定义登记处
BeanDefinitionRegistry源码注释
/**
* Interface for registries that hold bean definitions, for example RootBeanDefinition
* and ChildBeanDefinition instances. Typically implemented by BeanFactories that
* internally work with the AbstractBeanDefinition hierarchy.
* 登记处接口,该登记处保存着bean定义,如RootBeanDefinition、ChildBeanDefinition实例。被Bean工厂的子类实现
* <p>This is the only interface in Spring's bean factory packages that encapsulates
* <i>registration</i> of bean definitions. The standard BeanFactory interfaces
* only cover access to a <i>fully configured factory instance</i>.
*
* <p>Spring's bean definition readers expect to work on an implementation of this
* interface. Known implementors within the Spring core are DefaultListableBeanFactory
* and GenericApplicationContext.
*/
BeanDefinition
源码注释
/**
* A BeanDefinition describes a bean instance, which has property values,
* constructor argument values, and further information supplied by
* concrete implementations.
* BeanDefinition描述bean实例,BeanDefinition有属性值、构造器参数值、更多的信息由具体的实现提供
* <p>This is just a minimal interface: The main intention is to allow a
* {@link BeanFactoryPostProcessor} to introspect and modify property values
* and other bean metadata.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @since 19.03.2004
* @see ConfigurableListableBeanFactory#getBeanDefinition
* @see org.springframework.beans.factory.support.RootBeanDefinition
* @see org.springframework.beans.factory.support.ChildBeanDefinition
*/
Demo验证BeanDefinition到底是什么
@Service
public class UserA {
public void f1(){
System.out.println("userA f1...");
}
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(UserA.class);
BeanDefinition beanDefinition = annotationConfigApplicationContext.getBeanFactory().getBeanDefinition("userA");
System.out.println(beanDefinition);
}
}
断点展示beanDefinition内容
可以看到BeanDefinition存放了类的注册,全路径,scope范围等元信息
Bean创建过程
注册BeanDefinition到容器,登记bean名称
AbstractApplicationContext::refresh
先看看原文核心流程反应
// Prepare this context for refreshing.准备上下文用于刷新
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.准备bean工厂在上下文中使用
prepareBeanFactory(beanFactory);
// Allows post-processing of the bean factory in context subclasses.允许上下文子类中的bean工厂增强处理
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.调用工厂增强器在上下文中作为bean进行注册
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.注册bean增强器,该增强器能拦截bean创建
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.为上下文初始化事件播放器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.在特定上下文子类中,初始化其他bean
onRefresh();
// Check for listener beans and register them.检查监听bean并注册
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.初始化所有剩下的(非懒加载)单例
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.发布相应事件
finishRefresh();
从上文的注释中可以看到几个核心词汇:BeanFactoryPostProcessor--bean工厂增强器、BeanPostProcessor--bean增强器、ApplicationEventMulticaster--事件播放器、ApplicationListener-应用监听器。我们先看bean的初始化流程,后面再学习这些核心词汇涉及的内容。在构造函数设置断点
Bean创建序列图
从图中可以看到重点逻辑在AbstractAutowireCapableBeanFactory::doCreateBean
在这个过程中涉及到3个重要的单词:instantiate(实例化)-->populate(填值)-->initialize(初始化)
instantiate实例化
调用构造函数(默认构造函数或代参构造函数)分配内存并对普通成员变量(不需要依赖注入的变量)赋值
populate填值
成员变量中的@value @Autowired @Resource依赖查询赋值
initialize初始化
实现类的对应接口通知
- Aware(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware)接口
- BeanPostProcessor::postProcessBeforeInitialization
- InitializingBean::afterPropertiesSet、initMethod
- BeanPostProcessor::postProcessAfterInitialization
BeanPostProcessor::postProcessBeforeInitialization
跟进源码可以看到会对当前的所有PostProcesser遍历一边,调用Befroe方法
ApplicationContextAwareProcessor调用如下的Aware通知,常用的setApplicationContext获取上下午就是这儿通知的
CommonAnnotationBeanPostProcessor调用被@PostConstruct标注的函数
InitializingBean::afterPropertiesSet、initMethod
调用InitializingBean::afterPropertiesSet,调用@Bean注解上initMethod对应的方法
由上可知常见方法的调用顺序:
ApplicationContextAware::setApplicationContext-->@PostConstruct-->InitializingBean::afterPropertiesSet-->@Bean(initMethod)
总结
- 看源码一定要重视注释
- 纵向了解顶层接口或类的设计概念,顶层概念的框架图。再通过Bean创建过程,横向串联各个接口的业务关联。这也是面向抽象与面向过程的区别
- 可以自定义BeanPostProcessor在初始化之前和之后对Bean增强
- 阅读源码,不只是知道流程,还能够知道如何扩展