使用Spring的代码:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();
第一行代码,会构造一个ClassPathXmlApplicationContext对象,ClassPathXmlApplicationContext该如何理解,调用该构造方法除开会实例化得到一个对象,还会做哪些事情?
第二行代码,会调用ClassPathXmlApplicationContext的getBean方法,会得到一个UserService对象,getBean()是如何实现的?返回的UserService对象和我们自己直接new的UserService对象有区别吗?
第三行代码,就是简单的调用UserService的test()方法。
但是用ClassPathXmlApplicationContext其实已经过时了,在新版的Spring MVC和Spring Boot的底层主要用的都是AnnotationConfigApplicationContext,比如:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();
可以看到AnnotationConfigApplicationContext的用法和ClassPathXmlApplicationContext是非常类似的,只不过需要传入的是一个class,而不是一个xml文件。
Spring MVC创建的是XmlWebApplicationContext,和ClassPathXmlApplicationContext类似,都是基于XML配置的
Spring Boot创建的是AnnotationConfigApplicationContext
其实不管是AnnotationConfigApplicationContext还是ClassPathXmlApplicationContext,目前,我们都可以简单的将它们理解为就是用来创建Java对象的,比如调用getBean()就会去创建对象
在Java语言中,肯定是根据某个类来创建一个对象的。我们在看一下实例代码:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
当我们调用context.getBean(“userService”)时,就会去创建一个对象,但是getBean方法内部怎么知道"userService"对应的是UserService类呢?
三、Bean的创建过程一.Bean的生命周期
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
执行的时候首先会进行扫描、其次创建非懒加载的单例bean
初始化容器AnnotationConfigApplicationContext :
public AnnotationConfigApplicationContext(Class>... componentClasses) {
this();
this.register(componentClasses);
this.refresh();
}
进入到this()可以看到
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);//扫描器
}
StartupStep 是spring5.3之后新增的,功能相当于飞机的黑匣子,去记录运行代码锁消耗的时间,后续源码直接跳过。
再继续到refresh()方法里面的invokeBeanFactoryPostProcessors方法去实例化bdf(BeanDefinition)Map中的单例bean
1.扫描
首先进入到扫描器(ClassPathBeanDefinitionScanner)的scan方法
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
this.doScan(basePackages);
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}
这里用的bean注册器是BeandefinitionRegister,我们只需要扫描的功能。
重点是这个方法的doScan()方法继续进入
protected SetdoScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet(); String[] var3 = basePackages; int var4 = basePackages.length; //遍历扫描的包名, for(int var5 = 0; var5 < var4; ++var5) { String basePackage = var3[var5]; //核心方法findCandidateComponents Set candidates = this.findCandidateComponents(basePackage); Iterator var8 = candidates.iterator(); while(var8.hasNext()) { BeanDefinition candidate = (BeanDefinition)var8.next(); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate); } if (this.checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); this.registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
方法findCandidateComponents的原理是拿到扫描到的包路径,然后获取包路径下的单例Bean然后返回,我们进入到该方法
public SetfindCandidateComponents(String basePackage) { return this.componentsIndex != null && this.indexSupportsIncludeFilters() ? this.addCandidateComponentsFromIndex(this.componentsIndex, basePackage) : this.scanCandidateComponents(basePackage); }
这里用三元运算符,相当于一个if else,大部分情况下我们的spring工程都是走了else所以这里的核心方法是scanCandidateComponents(),我们继续点进去看(这里的if条件是去META-INE下找索引文件中是否有写索引文件,有的话直接去解析索引文件)
private SetscanCandidateComponents(String basePackage) { //这个LinkHashSet是最后返回的结果,所以这个方法就是往这里面添加元素 LinkedHashSet candidates = new LinkedHashSet(); try { String packageSearchPath = "classpath*:" + this.resolveBasePackage(basePackage) + '/' + this.resourcePattern; Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = this.logger.isTraceEnabled(); boolean debugEnabled = this.logger.isDebugEnabled(); Resource[] var7 = resources; int var8 = resources.length; for(int var9 = 0; var9 < var8; ++var9) { Resource resource = var7[var9]; if (traceEnabled) { this.logger.trace("Scanning " + resource); } try { MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource); if (this.isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) { if (debugEnabled) { this.logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } else if (debugEnabled) { this.logger.debug("Ignored because not a concrete top-level class: " + resource); } } else if (traceEnabled) { this.logger.trace("Ignored because not matching any filter: " + resource); } } catch (FileNotFoundException var13) { if (traceEnabled) { this.logger.trace("Ignored non-readable " + resource + ": " + var13.getMessage()); } } catch (Throwable var14) { throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var14); } } return candidates; } catch (IOException var15) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var15); } }
上述方法里面
- String packageSearchPath = “classpath*:” + this.resolveBasePackage(basePackage) + ‘/’ + this.resourcePattern
这里是拼接完整的类路径(this.resourcePattern = “**/*.class”; - Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);这里是拿到一个class的文件资源(类似于file对象)
- ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
this.setBeanClassName(this.metadata.getClassName());.//只是赋值名字,并没有加载类
this.setResource(metadataReader.getResource());
}
- 遍历资源,用元信息读取器metadataReader获取类元信息(类、资源、注解),判断是否为一个bean,符合条件的加入到Set里面
因为上述方法可以看出只有一处地方
if (this.isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
if (debugEnabled) {
this.logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
} else if (debugEnabled) {
this.logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
里面有两次的isCandidateComponent方法
第一次的isCandidateComponent:
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
Iterator var2 = this.excludeFilters.iterator();
TypeFilter tf;
do {
if (!var2.hasNext()) {
var2 = this.includeFilters.iterator();
do {
if (!var2.hasNext()) {
return false;
}
tf = (TypeFilter)var2.next();
} while(!tf.match(metadataReader, this.getMetadataReaderFactory()));
return this.isConditionMatch(metadataReader);
}
tf = (TypeFilter)var2.next();
} while(!tf.match(metadataReader, this.getMetadataReaderFactory()));
return false;
}
是将带有excludeFilters 和includeFilters进行筛选,spring默认会去注册一个includeFilters的component,然后再到isConditionMatch里面有一个shouldSkip方法(就是直接判断是否有Conditional注解(我们先忽略),没有就跳过)
第二次的isCandidateComponent:
public SetfindCandidateComponents(String basePackage) { return this.componentsIndex != null && this.indexSupportsIncludeFilters() ? this.addCandidateComponentsFromIndex(this.componentsIndex, basePackage) : this.scanCandidateComponents(basePackage); }
返回true的条件
1.isIndependent(顶级类or静态内部类=true)
2.isConcrete(接口=true)
3.isAbstract()&&hasAnnotatedMethods(Lookup.class.getName())(抽象类+存在lookup注解修饰的方法)
例如再java的class中
public static classA{
class B{
}
}
如这样的类被spring扫描到的话也能去实例化一个对象,
因为当A类被编译的时候实际上在文件夹下会出现A.class,A$B.class两个文件
这里我们直接回到的doscan方法那边,我们拿到了candidates(装有带component且符合条件的bean类的beanDefinition)
protected SetdoScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet(); String[] var3 = basePackages; int var4 = basePackages.length; //遍历扫描的包名, for(int var5 = 0; var5 < var4; ++var5) { String basePackage = var3[var5]; //核心方法findCandidateComponents Set candidates = this.findCandidateComponents(basePackage); Iterator var8 = candidates.iterator(); while(var8.hasNext()) { BeanDefinition candidate = (BeanDefinition)var8.next(); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);//解析单例or原型bean(注解上的scope属性默认单例) candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate); } if (this.checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); this.registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
继续往下走 ScopeMetadata是去解析component注解里面的scope(单例bean还是原型bean),这里看spring去创建beanName的思路进入方法generateBeanName()
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = this.determineBeanNameFromAnnotation((AnnotatedBeanDefinition)definition);
if (StringUtils.hasText(beanName)) {
return beanName;
}
}
return this.buildDefaultBeanName(definition, registry);
}
直接到determineBeanNameFromAnnotation()方法
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
Set types = amd.getAnnotationTypes();
String beanName = null;
Iterator var5 = types.iterator();
while(var5.hasNext()) {
String type = (String)var5.next();
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null) {
Set metaTypes = (Set)this.metaAnnotationTypesCache.computeIfAbsent(type, (key) -> {
Set result = amd.getMetaAnnotationTypes(key);
return result.isEmpty() ? Collections.emptySet() : result;
});
if (this.isStereotypeWithNameValue(type, metaTypes, attributes)) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String)value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
}
return beanName;
}
直接代码比较多其实就是去遍历类里面所有的注解,然后注解是否为component(在代码:this.isStereotypeWithNameValue(type, metaTypes, attributes)),再去判断value是否有设置值,有的话就用component注解里面的value作为beanName,如果没有就用类名第一个字母改成小写作为beanName(总的来说上面逻辑就是判断这个:如UserService如果component注解中value没有设置值那么beanName=userSerivce)
继续回到doscan方法里面的postProcessBeanDefinition方法
这个方法会给beandefinition里面赋一些初始的值(如是否懒加载这样的属性、@dependon等@Primary)
然后doscan里面的checkCandidate()方法是去检查容器中是否已经有beanName了初始化到BeanDefinitionHolder内,这里先跳过applyScopedProxyMode()方法beanDefinitions添加bdf然后注册到registerBeanDefinition里面最终注册到beandefinitionMap里面
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
} else {
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
if (this.isCompatible(beanDefinition, existingDef)) {
return false;
} else {
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() + "]");
}
}
}
总的来说这个方法通常是返回true,也就是第一个if去判断容器中是否有这个beanName没有的话返回true,如果已经存在其实大部分情况都是直接抛异常,除非符合isCompatible这个条件才会return false(是否兼容的方法),
在多次扫描的情况下,第一次已经生成了一部分的bdf了,然后在第二次进到这个方法的时候会发现存在(existingDef )然后执行isCompatible方法,具体步骤是去判断两个bdf的资源(resource)是否相同,bdf不同但是resource相同表示class是兼容的然后返回false,不去注册到容器中。
因此spring的扫描逻辑到这里就结束了。
总结一下扫描的逻辑
扫描器->scan->doscan->findCandidateComponents(找到符合条件且带有component注解的类)->生成beanName(用类名首字母小写或者component里面value的值)->beanDefinition初始化一些属性->判断bdf与容器是否兼容(两个相同beanName的bdf是否有相同的resource)->注册到容器(兼容的bdf不注册)
2.创建非懒加载的单例bean
我们进到容器的refresh方法的finishBeanFactoryInitialization方法的preInstantiateSingletons()方法,顾名思义创建单例bean
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Pre-instantiating singletons in " + this);
}
List beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator();
while(true) {
String beanName;
Object bean;
do {
while(true) {
RootBeanDefinition bd;
do {
do {
do {
if (!var2.hasNext()) {
var2 = beanNames.iterator();
while(var2.hasNext()) {
beanName = (String)var2.next();
Object singletonInstance = this.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(() -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
return;
}
beanName = (String)var2.next();
bd = this.getMergedLocalBeanDefinition(beanName);
} while(bd.isAbstract());
} while(!bd.isSingleton());
} while(bd.isLazyInit());
if (this.isFactoryBean(beanName)) {
bean = this.getBean("&" + beanName);
break;
}
this.getBean(beanName);
}
} while(!(bean instanceof FactoryBean));
FactoryBean> factory = (FactoryBean)bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
SmartFactoryBean var10000 = (SmartFactoryBean)factory;
((SmartFactoryBean)factory).getClass();
isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
} else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
}
if (isEagerInit) {
this.getBean(beanName);
}
}
}
由于源码中do while嵌套太繁琐化简来看
代码中第一个do-while:
do{...} while(!(bean instanceof FactoryBean));
也就是不为FactoryBean的时候循环do里面的逻辑
代码中第二个do-while:
do {
while(true) {
RootBeanDefinition bd;
do {...}while(bd.isLazyInit());
if (this.isFactoryBean(beanName)) {
bean = this.getBean("&" + beanName);
break;
}
this.getBean(beanName);
}
} while(!(bean instanceof FactoryBean));
非懒加载的bean走do循环逻辑
以此类推,最里面的do逻辑要求是非懒加载的单例bean+!isAbstract(且还得是抽象的beandefinition,正常情况定义的bean的beandefinition都不是抽象的只有在xml里面bean标签配置的bean abstract=true的时候创建的beandefintion是抽象的)
例如以下情况
那么userService的beandefinition继承了user的beandefinition,因此userService也是多例的
我们看到getMergedLocalBeanDefinition()方法
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
RootBeanDefinition mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);
return mbd != null && !mbd.stale ? mbd : this.getMergedBeanDefinition(beanName, this.getBeanDefinition(beanName));
}
会将user和userService的beanDefinition合并成一个rootBeanDefintiion,也就是去生成第三个beanDefintion并不会改变他们自己的beanDefintion,然后userService的属性会放在rootbdf里面,然后将rootbdf存到mergedBeanDefinitions里面去
然后我们在看到getMergedBeanDefinition()方法
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException {
synchronized(this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
if (containingBd == null) {
mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition)bd).cloneBeanDefinition();
} else {
mbd = new RootBeanDefinition(bd);
}
} else {
BeanDefinition pbd;
try {
String parentBeanName = this.transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = this.getMergedBeanDefinition(parentBeanName);
} else {
BeanFactory parent = this.getParentBeanFactory();
if (!(parent instanceof ConfigurableBeanFactory)) {
throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without a ConfigurableBeanFactory parent");
}
pbd = ((ConfigurableBeanFactory)parent).getMergedBeanDefinition(parentBeanName);
}
} catch (NoSuchBeanDefinitionException var11) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", var11);
}
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope("singleton");
}
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
if (containingBd == null && this.isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
this.copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
这里的逻辑也比较复杂,我们直接看到
if (!beanName.equals(parentBeanName)) {
pbd = this.getMergedBeanDefinition(parentBeanName);
}
这里是用了递归有可能userService的父亲user还有父亲所以user要先跟那他的父亲去合并。核心就是合并逻辑。去生成一个新的rootbd
margedbdmap这个是非常重要的,后续很多beanName获取bd都是先去mbdMap里面去拿合并后的rootbd
我们再回到preInstantiateSingletons方法里的一段代码
while(var2.hasNext()) {
beanName = (String)var2.next();
Object singletonInstance = this.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(() -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
这里是再去循环这些beanName,然后判断是否实现了SmartInitializingSingleton这个接口,如果实现了回去调用
类里面的afterSingletonsInstantiated()方法
然后我们在看到isFactoryBean()方法
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = this.transformedBeanName(name);
Object beanInstance = this.getSingleton(beanName, false);
if (beanInstance != null) {
return beanInstance instanceof FactoryBean;
} else {
return !this.containsBeanDefinition(beanName) && this.getParentBeanFactory() instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory)this.getParentBeanFactory()).isFactoryBean(name) : this.isFactoryBean(beanName, this.getMergedLocalBeanDefinition(beanName));
}
}
getSingleton()方法一开始是拿不到对象的,factoryBean生成的对象是两个对象分别是demoFactoryBean以及getObject返回的对象,getSingleton拿的是demoFactoryBean,然后判断是否实现FactoryBean
然后else逻辑是去判断本BeanFactory里面是有bd如果没有那么再去父BeanFactory里面去找bd(用代码解释如下)
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setParent(parent);
context.getBean("a1");
就是当context容器(子BeanFactory)里面去那a1的时候会先去判断是否有parentBeanFactory(上诉代码给context容器设置parent为parent容器)就会直接去parent里面找a1的bd



