前言
由于本人也是刚开始学习Spring源码,欢迎各位大佬指导。
Bean对象生命周期流程图
扫描过程:
ApplicationContext创建
通过创建一个AnnotationConfigApplicationContext容器来进行分析:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class)
点开查看这个构造器源码
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
this();
register(componentClasses);
refresh();
}
在this()方法中,构造了两个关键的东西,一个是reader ,一个是scaner
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
那Spring容器的扫描是怎么进行的呢? 是的,其实就是调用了this.scanner中的scan()方法进行扫描,具体来看一下吧
scanner中的scan()方法
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
核心代码就在于这个doScan()方法,是进行真正的扫描
核心扫描方法:doScan()
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器中是否已经存在该beanName
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
1. 扫描BeanDefiniton对象方法:findCandidateComponents()
我们先进行分析findCandidateComponents()这个方法, 通过返回值我们可以得出,这个就是来扫描BeanDefinition对象。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
addCandidateComponentsFromIndex(this.componentsIndex, basePackage)
一般不会走该方法,如果你自己定义了一个索引,则会进行这里的逻辑
具体源码如下:
大体逻辑和下面 scanCandidateComponents(basePackage)类似,只是有个索引的作用,可以通过该索引直接去查找对于路径下的注解,生成bean,重点分析下面的那个方法
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
Set<String> types = new HashSet<>();
for (TypeFilter filter : this.includeFilters) {
// Component注解
String stereotype = extractStereotype(filter);
if (stereotype == null) {
throw new IllegalArgumentException("Failed to extract stereotype from " + filter);
}
types.addAll(index.getCandidateTypes(basePackage, stereotype));
}
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (String type : types) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(metadataReader.getResource());
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Using candidate component class from index: " + type);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + type);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because matching an exclude filter: " + type);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
scanCandidateComponents(basePackage)
思考一下,我们怎么进行扫描呢?
(大概流程) 首先会根据路径获取该路径下的所有资源,然后在通过遍历每一个resource对象,扫描到该对象的一些注解,确认是否可以成为一个bean对象,然后在进行注入。
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// excludeFilters、includeFilters判断
if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
大致流程
大致流程如下图:https://www.processon.com/v/64db3d1028344d578df63b77
1.首先通过遍历出每个resource后,获得他们的原空间对象metadataReader对象
2.通过metadataReader对象,进行excludeFilters、includeFilters判断
3.通过后在根据metadataReader对象判断是否独立、是否是接口、是否是抽象类并且含有@Lookup注解
4.都通过后添加BeanDefinition对象
isCandidateComponent(MetadataReader metadataReader)
让我们来分析 isCandidateComponent(MetadataReader metadataReader)源码
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
定义了两个List<TypeFilter> 用来存储 includeFilter 和 excludeFilter信息,如果要是在exclude的字段,将返回false,然后不做处理,如果要是include的字段,返回结果是在于 isConditionMatch()这个方法。
可能大家有疑问。为什么项目中我明明什么都没指定,但是一样会产生bean对象呢?
原因在于,Spring在初始化scaner时,添加了@component注解为默认的includeFilter字段
大家可以在ApplicationContext的构造方法的this()方法中找到scanner的构造方法,然后一步步点进去,直到registerDefaultFilters()这个方法
让我们再回到刚刚判断includeFilters的地方,刚刚我们提到了返回值是一个方法,让我们来分析一下该方法
shouldSkip
进入到对应的shouldSkip(metadata, null)
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
其实这段代码主要是判断是否有@conditonal这个注解
如果没有的话,返回false,由于前面的返回值取得是非值,即为true,这样就正常生成了BeanDefiniton对象。
如果有的话,会走下面的逻辑,下面的逻辑大概是将会执行conditon类的matches()方法,然后根据返回值来判断。
扩展一下:@conditonal注解
我们通过简单的操作来看一下@conditonal注解的作用。
这是我的项目结构:
首先创建一个自己的conditon类
public class TestConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
context.getClassLoader().loadClass("com.zhouyu.service.User");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
创建一个配置类
@ComponentScan(value = "com.zhouyu")
public class AppConfig {
}
创建一个UserService类,添加Conditional注解
@Component
@Conditional(TestConditional.class)
public class UserService {
public UserService() {
}
public void test(){
System.out.println();
}
}
然后我们通过AppConfig这个配置类来获取userService对象。
先猜测一下,肯定是能获得的,因为我们项目中有User这个类,然后TestConditonal返回的肯定是true。
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
运行结果:
但如果我们修改一下 TestConditional 。让他返回false呢
public class TestConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
context.getClassLoader().loadClass("com.zhouyu.service.User1");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
我们通过加载器加载User1这个对象,首先我们的项目里并没有User1这个对象,因此一定会发生错误,也就是会返回false,让我们再看一下结果
结果显而易见,没有找到userService这个bean对象
归根结底就是这个@conditonal注解返回的是false,返回刚刚源码的地方,是不是很容易理解刚刚的话了。
isCandidateComponent(AnnotatedBeanDefinition beanDefinition)
回到源码,继续往下走,又到了一个判断。
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
isIndependent:到底是顶级类还是嵌套类(静态内部类),可以独立于外部类构造
isConcrete:是否是接口
isAbstract:是否是抽象类
hasAnnotatedMethods(Lookup.class.getName()):是否有Lookup注解
都通过后就添加BeanDefinition对象
扩展@Lookup用法:
通过上面的判断,判断是否是抽象类&&是否有Lookup注解,我们不妨来测试一下。
定义UserService类为抽象类,看是否能获取bean对象
@Component
//@Conditional(TestConditional.class)
public abstract class UserService {
@Autowired
private User user;
public void test(){
System.out.println(user);
}
}
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
打印结果:
但如果我们加入@Lookup注解
@Component
//@Conditional(TestConditional.class)
public abstract class UserService {
@Autowired
private User user;
public void test(){
System.out.println(user);
}
@Lookup("user")
public void a(){
}
}
运行结果:就可以拿到这个抽象类的bean对象了
另一个用法,我们定义User对象为prototype,UserService对象为单例bean时,如果userService调用方法生成user对象时,这个user对象是否为同一个呢?
@Component
@Scope("prototype")
public class User {
}
@Component
//@Conditional(TestConditional.class)
public class UserService {
@Autowired
private User user;
public void test(){
System.out.println(user);
}
/*
@Lookup("user")
public void a(){
}*/
}
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
userService.test();
userService.test();
打印结果:为同一个对象,原因是由于userService对象是单例的,因此不管userService是否为原型bean,只赋值一次,也就是打印的是同一个对象了
我们修改一下代码:
@Component
//@Conditional(TestConditional.class)
public class UserService {
@Autowired
private User user;
public void test(){
System.out.println(a());
}
@Lookup("user")
public User a(){
return null;
}
}
打印结果:不同的bean对象
2. 扫描获得的BeanDefinition对象赋予一些默认值 postProcessBeanDefinition()
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
// 设置BeanDefinition的默认值
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
// AutowireCandidate表示某个Bean能否被用来做依赖注入
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
public void applyDefaults(BeanDefinitionDefaults defaults) {
Boolean lazyInit = defaults.getLazyInit();
if (lazyInit != null) {
setLazyInit(lazyInit);
}
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
3.解析@Lazy、@Primary、@DependsOn、@Role、@Description注解
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
4.检查Spring容器中是否已经存在该beanName
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
// 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
5.注册(注册到了BeanDefinitionMap中)
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
初始化非懒加载单例bean
通过 finishBeanFactoryInitialization(beanFactory)进去,找到beanFactory.preInstantiateSingletons() 方法
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
// 获取合并后的BeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 获取FactoryBean对象
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) {
// 创建真正的Bean对象(getObject()返回的对象)
getBean(beanName);
}
}
}
else {
// 创建Bean对象
getBean(beanName);
}
}
}
// 所有的非懒加载单例Bean都创建完了后
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
首先先了解 RootBeanDefinition ,他是后来生产的合并的BeanDefinition,比如:
<bean id="user" class="com.zhouyu.service.User" abstract="true" scope="prototype"/>
<bean id="userService" class="com.zhouyu.service.UserService" parent="user"/>
user是原型,userService是单例的(默认),然后userService的parent是user,那userService是单例还是原型?
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
UserService userService1 = (UserService) applicationContext.getBean("userService");
UserService userService2 = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
System.out.println(userService1);
System.out.println(userService2);
运行结果: userService采用了它父BeanDefinition的属性。然后Spring创建的时候不能更改user以及userService的属性,是采用创建了RootBeanDefinition来进行合并生成第三个BeanDefinition
并且合并的流程先不分析,感兴趣的朋友可以看看,也是挺简单。
下一步拿着合并后的BeanDefinition对象来判断是否是抽象的BeanDefinition、是否是懒加载的、是否是单例的,都通过后,才真正的创建Bean对象: getBean(beanName)
下一步都所有的非抽象、非懒加载的单例bean创建完成后,对于实现了SmartInitializingSingleton 的接口的bean对象,执行 smartSingleton.afterSingletonsInstantiated()方法