详解Spring的GetBean⽅法
Spring容器提供了五种获取Bean的⽅式,可以根据beanName获取Bean,也可以根据classType来获取Bean,所有根据beanName来获取Bean的⽅式,底层都会通过调⽤下⾯的doGetBean()来获取Bean对象
protected<T> T doGetBean(
String name,@Nullable Class<T> requiredType,@Nullable Object[] args,boolean typeCheckOnly)
⼀、根据beanName获取Bean
Spring容器提供了三种根据beanName获取Bean的⽅式:
收敛性
// 启动Spring容器
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(AppConfig.class);
// 直接根据beanName来获取
UrService urService =(UrService) Bean("urService");
// 根据beanName获取Bean后,判断该Bean是否属于UrService类型
UrService urService1 =(UrService) Bean("urService",UrService.class);
// 指定构造⽅法参数,使⽤指定的构造⽅法的⽣成Bean,如果UrService是单例的,则容器启动的过程中就会去⾃⾏推断构造⽅法然后创建单例Bean;如果UrSer vice是原型的,则每次都会getBean()时,会根据后⾯提供的构造⽅法参数使⽤指定的构造⽅法创建Bean
UrService urService2 =(UrService) Bean("urService",new OrderService());
上⾯三种⽅式都会调⽤doGetBean()来获取Bean对象,下⾯将详细介绍doGetBean()的实现
protected<T> T doGetBean(
String name,@Nullable Class<T> requiredType,@Nullable Object[] args,boolean typeCheckOnly)
throws BeansException {
// name有可能是 &xxx 或者 xxx,如果name是&xxx,那么beanName就是xxx
// name有可能传⼊进来的是别名,那么beanName就是id
String beanName =transformedBeanName(name);
西安注册会计师培训Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance =getSingleton(beanName);
if(sharedInstance !=null&& args ==null){
// 如果sharedInstance是FactoryBean,那么就调⽤getObject()返回对象
beanInstance =getObjectForBeanInstance(sharedInstance, name, beanName,null);
}
上述代码在的FactoryBean创建部分有⼤概介绍过,下⾯将详细介绍核⼼的代码⽅法
1.1 name转换,获取真正的beanName
transformedBeanName()主要将传进来的name转换成真正的beanName,具体实现如下:
protected String transformedBeanName(String name){
return ansformedBeanName(name));
}
先看⾥⾯的ansformedBeanName()实现,下⾯代码在FactoryBean的创建中已经讲过,想要获取⼀个FactoryBean 的对象,那么传进来的name是以“&”前缀开头,可以只有⼀个“&”,也可以有多个“&”,下⾯的代码只是将前缀的“&”去掉⽽已
public static String transformedBeanName(String name){
if(!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)){
return name;
}
puteIfAbnt(name, beanName ->{
do{
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
接下来看canonicalName()实现了怎样的功能,调⽤ansformedBeanName()返回的可能还不是最终的beanName,可能是Bean的⼀个别名,使⽤@Bean注解创建Bean的时候,可以为Bean指定多个名称,如下所⽰:
Spring会把第⼀个名字即“urService”作为真正的beanName,⽽后⾯的名字作为Bean的别名进⾏存
储
@Bean({"urService","urService1"})
public UrService urService(){
return new UrService();
}
panache
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(AppConfig.class);
朋友用英语怎么写//根据别名也能获取Bean
UrService urService =(UrService) Bean("urService1");
Bean的别名存放在⼀个aliasMap中,其中KEY=别名,VALUE=beanName/别名,根据别名从aliasMap中拿到的可能是真正的beanName,也可能还是⼀个别名,所以⽤do-while循环,直到拿出来的名字从aliasMap再找不到对应的值,那么该名字就是真正的beanName了
public String canonicalName(String name){
String canonicalName = name;
//
String resolvedName;
do{
resolvedName =(canonicalName);
if(resolvedName !=null){
canonicalName = resolvedName;
}
}
while(resolvedName !=null);
return canonicalName;
}
1.2 ⽗BeanFactory创建Bean对象
获取到真正的beanName之后,不论是单例Bean还是原型Bean,都会调⽤getSingleton(beanName)去单例池中查找是否有单例Bean。如果从单例池中取出对象了,接下来的getObjectForBeanInstance()主要根据原始name判断当前Bean是否是FactoryBean,以及获取FactoryBean对象。如果单例池中不存在,则需要创建Bean实例
如果当前BeanFactory的beanDefinitionMap中不存在该beanName,且存在parentBeanFactory,则让parentBeanFactory去创建Bean
BeanFactory parentBeanFactory =getParentBeanFactory();
if(parentBeanFactory !=null&&!containsBeanDefinition(beanName)){
// Not found -> check parent.
// &&&&xxx---->&xxx
String nameToLookup =originalBeanName(name);
if(parentBeanFactory instanceof AbstractBeanFactory){
return((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
el if(args !=null){
// Delegation to parent with explicit args.
return(T) Bean(nameToLookup, args);
}
el if(requiredType !=null){
// No args -> delegate to standard getBean method.
Bean(nameToLookup, requiredType);
}
el{
return(T) Bean(nameToLookup);
}
}
originalBeanName(name)⽅法⽤于将别名和"&&&"格式的名字进⾏转换真正的beanName或FactoryBean的beanName
protected String originalBeanName(String name){
String beanName =transformedBeanName(name);
if(name.startsWith(FACTORY_BEAN_PREFIX)){
beanName = FACTORY_BEAN_PREFIX + beanName;
}
return beanName;
}
1.3 当前BeanFactory来创建Bean
从mergedBeanDefinitions中根据beanName获取RootBeanDefinition,中提到过真正创建Bean的时候,⽤的是合并后的RootBeanDefinition⽽不是普通的BeanDefinition
然后判断当前RootBeanDefinition是否是抽象的,如果是抽象的将会抛出异常
接着获取该Bean的@DependsOn注解依赖的beanName
创建@DependsOn注解依赖Bean对象
RootBeanDefinition mbd =getMergedLocalBeanDefinition(beanName);
// 检查BeanDefinition是不是Abstract的
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = DependsOn();
DependsOn注解的使⽤如下:
DependsOn注解指明在创建UrServicce的Bean之前,需要先创建orderService和ur,在Spring⽣成BeanDefinition的时候,就回去解析@DependsOn,然后将依赖的beanName存放在BeanDefinition的字符串数组dependsOn中
@Component
@DependsOn({"orderService","ur"})
public class UrService {
}
如果DependsOn数组不为空,将遍历数组,⾸先判断是否存在@DependsOn的循环依赖(这个地⽅的循环依赖不同于依赖注⼊的循环依赖),即UrService依赖于ur,⽽Ur的@DependsOn⼜依赖于urService,对于这种情况,将直接抛出异常
如果不存在循环依赖,则把这种依赖关系存放在dependentBeanMap中,它的key表⽰被依赖Bean的beanName,⽽value是⼀个Set,存放依赖该Bean的beanName集合,然后调⽤getBean(dep)来创建依赖的Bean对象
if(dependsOn !=null){
// dependsOn表⽰当前beanName所依赖的,当前Bean创建之前dependsOn所依赖的Bean必须已经创建好了
for(String dep : dependsOn){
// beanName是不是被dep依赖了,如果是则出现了循环依赖
if(isDependent(beanName, dep)){
throw new ResourceDescription(), beanName,
"Circular depends-on relationship between '"+ beanName +"' and '"+ dep +"'");
}
/
/ dep被beanName依赖了,存⼊dependentBeanMap中,dep为key,beanName为value
registerDependentBean(dep, beanName);establishing
// 创建所依赖的bean
try{
getBean(dep);
}
catch(NoSuchBeanDefinitionException ex){
throw new ResourceDescription(), beanName,
"'"+ beanName +"' depends on missing bean '"+ dep +"'", ex);
}
打电话的技巧}
}
创建单例Bean
如果RootBeanDefinition的scope属性是单例的,则调⽤getSingleton创建单例Bean
if(mbd.isSingleton()){
sharedInstance =getSingleton(beanName,()->{
try{
return createBean(beanName, mbd, args);
}
catch(BeansException ex){
destroySingleton(beanName);
throw ex;
}
});
// 前⾯讲过,主要⽤于获取FactoryBean
beanInstance =getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
getSingleton(beanName, ObjectFactory<?> singletonFactory)先从单例池中根据beanName来获取单例Bean,如果单例池中没有,则再通过createBean来创建单例Bean
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory){
synchronized(this.singletonObjects){
出品英文Object singletonObject =(beanName);
if(singletonObject ==null){
……
try{
// 通过lambda表达式调⽤createBean⽅法
singletonObject = Object();
newSingleton =true;
}
……
// 添加到单例池
if(newSingleton){
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
创建原型Bean
如果RootBeanDefinition的scope属性是原型的,则直接调⽤createBean⽅法创建原型Bean
if(mbd.isPrototype()){
// It's a prototype -> create a new instance.
Object prototypeInstance =null;
try{
beforePrototypeCreation(beanName);
prototypeInstance =createBean(beanName, mbd, args);
}
finally{
afterPrototypeCreation(beanName);
}诚然
beanInstance =getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
创建其他作⽤域Bean
除了单例和原型Bean,Spring还⽀持request、ssion和application作⽤域的Bean
⾸先获取scopeName,然后根据scopeName获取对应的Scope对象,⽐如:RequestScope和SessionScope
Scope对象的get⽅法都会去调⽤AbstractRequestAttributesScope类的get(),RequestScope和SessionScope都继承该类
String scopeName = Scope();
Scope scope =(scopeName);
if(scope ==null){
throw new IllegalStateException("No Scope registered for scope name '"+ scopeName +"'");
}
try{// Attriute(beaName) tAttri
Object scopedInstance = (beanName,()->{
beforePrototypeCreation(beanName);
try{
return createBean(beanName, mbd, args);
}
finally{
afterPrototypeCreation(beanName);
}
});
beanInstance =getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
考研政治真题及答案getScope()返回Scope对象对应的Scope值,然后调⽤getAttribute⽅法,如果request和ssion中都没有Bean实例,
public Object get(String name, ObjectFactory<?> objectFactory){
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
Object scopedObject = Attribute(name,getScope());
if(scopedObject ==null){
// lambda表达式调⽤createBean创建实例
scopedObject = Object();
// 并将Bean设置到对应的属性中
attributes.tAttribute(name, scopedObject,getScope());
……
}
英语长篇故事
return scopedObject;
}
getAttribute根据传进来的Scope值,判断从request还是ssion去根据name获取对应属性的对象
public Object getAttribute(String name,int scope){
if(scope == SCOPE_REQUEST){
if(!isRequestActive()){
throw new IllegalStateException(
"Cannot ask for request attribute - request is not active anymore!");
}
Attribute(name);