1. 什么是beanFactory
beanFactory
从名称上来看,它的意思是bean 工厂
,它是生产 bean
与保存 bean (针对单例 bean)
的地方。
我们先来看看beanFactory
提供了哪些方法:
public interface BeanFactory {
/**
* factoryBean使用
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 根据名称获取bean
*/
Object getBean(String name) throws BeansException;
/**
* 根据名称获取bean
*/
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
/**
* 根据名称获取bean
*/
Object getBean(String name, Object... args) throws BeansException;
/**
* 根据类型获取bean
*/
<T> T getBean(Class<T> requiredType) throws BeansException;
/**
* 根据类型获取bean
*/
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
/**
* 获取BeanProvider
*/
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
/**
* 获取BeanProvider
*/
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
/**
* 是否包含bean
*/
boolean containsBean(String name);
/**
* 是否为单例bean
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 是否为原型bean
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 判断类型是否匹配
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch)
throws NoSuchBeanDefinitionException;
/**
* 判断类型是否匹配
*/
boolean isTypeMatch(String name, Class<?> typeToMatch)
throws NoSuchBeanDefinitionException;
/**
* 根据名称获取bean的类型
*/
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 根据名称获取bean的类型
*/
@Nullable
Class<?> getType(String name, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException;
/**
* 根据bean名称获取bean的别名
*/
String[] getAliases(String name);
}
复制代码
BeanFactory
接口定义了beanFactory
的基本操作,可以看到,其提供了非常多的getBean(...)
方法。
我们再看看看beanFactory
的继承关系:
可以看到,beanFactory
经过了重重继承,功能也由其子接口一步步扩展,接口提供功能,类来进行实现,最终得到的是DefaultListableBeanFactory
,这也是 spring 默认使用的beanFactory
。
我们来看看这些接口的功能:
BeanFactory
:最基本的BeanFactory
,定义了基本的操作HierarchicalBeanFactory
:提供了继承功能,用来获取ParentBeanFactory
(设置ParentBeanFactory
的操作在ConfigurableBeanFactory
中)ListableBeanFactory
:提供list
操作,如列出符合条件的BeanName
、Bean
ConfigurableBeanFactory
:提供配置操作,如设置ParentBeanFactory
、设置BeanClassLoader
、设置BeanClassLoader
等AutowireCapableBeanFactory
:提供bean的手动注入功能,如createBean(Class)
可以将Class
初始化spring bean,autowireBean(Object)
可以将一个java实例初始化成spring beanConfigurableListableBeanFactory
:组合了ListableBeanFactory
与ConfigurableBeanFactory
接口的功能
最后是DefaultListableBeanFactory
,这个类实现了以上的所有接口,包含了上面的所有功能,接下来我分析我们基本都是基于这个类。
2. DefaultListableBeanFactory
spring 的 applicationContext
中默认的 beanFactory
就是 DefaultListableBeanFactory
,因此这个类非常非常重要,这里我们简单列举下平时经常用到的属性:
beanDefinitionMap
:存放beanDefinition
的Map
beanDefinitionNames
:存放beanDefinition
名称的List
singletonObjects
:继承自DefaultSingletonBeanRegistry
类,存放单例bean
的map
在 beanFactory
中,最重要的内容要算beanDefinition
与singletonBean
了,DefaultListableBeanFactory
中有各自对应的结构来存储这些。接下来我们再看看一些重要的方法:
方法 | 说明 |
---|---|
DefaultSingletonBeanRegistry#addSingleton(String, Object) | 手动添加一个单例 bean 到 beanFactory 中 |
AbstractAutowireCapableBeanFactory#createBean(Class<?>, int, boolean) | 手动创建一个spring bean (有完整的spring bean 生命周期,即实例化、属性注入、初始化等) |
AbstractAutowireCapableBeanFactory#autowire(Class<?>, int, boolean) | 创建对应的Class实例后,再对其属性注入(只有两个操作:实例化、属性注入) |
AbstractAutowireCapableBeanFactory#autowireBean(Object) | 对传入的bean进行属性注入(只有属性注入操作) |
BeanFactory#getBean(String, ...) | 根据bean的名称 获取对应的bean ,如果该bean 不存在但对应的beanDefinition 存在,则创建bean,如果对应的beanDefinition 也不存在,则抛出异常,该方法拥有众多的重载方法 |
BeanFactory#getBean(Class<T>, ...) | 根据bean的类型 获取对应的 bean ,如果bean不存在则抛出异常,如果找到多个bean 且未指定primary 也会抛出异常,该方法也有众多的重载方法 |
DefaultListableBeanFactory#getBeanDefinition(String) | 根据bean的名称 获取一个beanDefinition |
DefaultListableBeanFactory#getBeanNamesForType(Class<?>) | 根据类型获取bean的名称 ,返回值为数组,可以返回多个名称 |
DefaultListableBeanFactory#getBeansOfType(Class<T>) | 根据类型获取bean ,返回值为Map ,可以返回多个bean ,Map 的key 为bean 的名称,value 为bean |
3. 代码示例:spring 下的策略模式
示例:在支付项目中,我们可能同时要接入微信、支付宝、银联支付、苹果支付等,如果我们像这样来处理支付:
if(微信支付) {
// 处理微信支付操作
} else if(支付宝支付) {
// 处理支付宝支付操作
} else if(...) {
...
}
复制代码
后续接入了新的支付方式后,这个if-else
也要不断往下加,对于这么多的if-else
,聪明如你一定想到使用策略模式来进行优化,这里我们来看看spring 容器结合策略模式的妙用。
3.1 List
注入
准备一个Constant
类,里面就两个常量:
public abstract class Constant {
/**
* 微信支付方式
*/
public static final String WX_PAY = "wx";
/**
* 支付宝支付方式
*/
public static final String ALI_PAY = "ali";
}
复制代码
定义一个接口,处理主要操作:
public interface IPayService {
/**
* 判断当前service是否支持处理
* @param context 将所有的参数封装在 context 中
* @return
*/
boolean support(BizContext context);
/**
* 具体的处理操作
* @return
*/
void handler();
}
复制代码
BizContext
内容如下:
public class BizContext {
/**
* 支持方式
*/
private String payWay;
// 省略 get 与 set 方法
}
复制代码
这个类用来封装参数,虽然目前只有一个参数,但实际业务中会有多个,可以统一放在这个类里。
接着是接口的两个实现类:
/**
* 处理微信支付
*/
@Service
public class WxPayService implements IPayService {
@Override
public boolean support(BizContext context) {
return Constant.WX_PAY.equals(context.getPayWay());
}
@Override
public void handler() {
System.out.println("处理微信支付");
}
}
/**
* 处理支付宝支付
*/
@Service
public class AliPayService implements IPayService {
@Override
public boolean support(BizContext context) {
return Constant.ALI_PAY.equals(context.getPayWay());
}
@Override
public void handler() {
System.out.println("处理支付宝支付");
}
}
复制代码
准备一个业务类:
@Service
public class BizService {
/**
* 注入 List
*/
@Autowired
private List<IPayService> payServiceList;
/**
* 处理类
*/
public void handler(String payWay) {
// 准备参数
BizContext context = new BizContext();
context.setPayWay(payWay);
// 遍历,找到支持当前参数的类
for(IPayService payService : payServiceList) {
if(payService.support(context)) {
payService.handler();
return;
}
}
throw new IllegalArgumentException("支付方式不支持");
}
}
复制代码
主类:
@ComponentScan
public class Demo03Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext();
context.register(Demo03Main.class);
context.refresh();
BizService bizService = (BizService) context.getBean("bizService");
// 通过改变传入参数来确定最终使用哪个类来处理
bizService.handler(Constant.ALI_PAY);
// bizService.handler(Constant.WX_PAY);
}
}
复制代码
运行,结果如下:
处理支付宝支付
复制代码
这个示例比较简单,主要是通过@Autowired
注入一个List<IPayService>
,然后遍历这个List
,找到能处理当前参数的IPayService
,再执行其handler(...)
方法。
可以看到,如果使用spring
,我们根本不必关心策略类的注册,注册操作spring已经为我们处理好了,后续我们不管有多少的支付方式,只需实现IPayService
,然后重写相应的方法就行了,原来的代码不必改动,扩展性大大地提高了。
值班一提的,这种**support(...)
方法判断能否处理、handler(...)
方法进行具体操作**的方式在 spring mvc 中进行了大量地运用,如运行 controller
方法前的参数解析、处理 @ResponseBody
的返回值。
3.2 使用 getBeansOfType(Class<T>)
方法
我们再来分析上面的业务,我们发现判断条件并不复杂,不必单独使用一个方法来判断,我们也可以直接指定一个业务类型,用指定的IPayService
处理指定的类型就可以了。
这次我们的IPayService
改成这样:
public interface IPayService {
/**
* 返回当前service支持的类型
* @return
*/
String getPayWay();
/**
* 具体的处理操作
* @return
*/
void handler();
}
复制代码
然后两个业务类这样写:
/**
* 处理微信支付
*/
@Service
public class WxPayService implements IPayService {
@Override
public String getPayWay() {
return Constant.WX_PAY;
}
@Override
public void handler() {
System.out.println("处理微信支付");
}
}
/**
* 处理支付宝支付
*/
@Service
public class AliPayService implements IPayService {
@Override
public String getPayWay() {
return Constant.ALI_PAY;
}
@Override
public void handler() {
System.out.println("处理支付宝支付");
}
}
复制代码
业务类里需要手动加载IPayService
的bean
:
@Service
public class BizService implements ApplicationContextAware {
/**
* 保存IPayService的map
* key 是 能处理的类型,value 是具体的 service
*/
private volatile Map<String, IPayService> payServiceMap;
// 这个是为了调用 getBeansOfType 方法
private ApplicationContext applicationContext;
/**
* 具体的处理操作
*/
public void handler(String payWay) {
IPayService payService = getPayService(payWay);
payService.handler();
}
/**
* 获取 PayService
*/
private IPayService getPayService(String payWay) {
// 加载所有 IPayService 到 payServiceMap,只需要加载一次
if(null == payServiceMap) {
synchronized (this) {
if(null == payServiceMap) {
// 获取所有 IPayService 类型的 bean
// 最终调用的是 DefaultListableBeanFactory#getBeansOfType(Class<T>)
Map<String, IPayService> beansOfType
= applicationContext.getBeansOfType(IPayService.class);
// 构建 payServiceMap
Map<String, IPayService> map = new HashMap<>(beansOfType.size());
for(Map.Entry<String, IPayService> entry : beansOfType.entrySet()) {
IPayService payService = entry.getValue();
map.put(payService.getPayWay(), payService);
}
payServiceMap = map;
}
}
}
// 之后只需直接从 payServiceMap 中获取即可
IPayService payService = payServiceMap.get(payWay);
if(null == payService) {
throw new IllegalArgumentException("支付方式不支持");
}
return payService;
}
/**
* 获取 applicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
复制代码
主类也基本不变:
@ComponentScan
public class Demo04Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Demo04Main.class);
context.refresh();
BizService bizService = (BizService) context.getBean("bizService");
bizService.handler(Constant.ALI_PAY);
// bizService.handler(Constant.WX_PAY);
}
}
复制代码
运行,结果如下:
处理支付宝支付
复制代码
可以看到,这种方式也能根据传入的参数进行对应的处理操作。
这种方式先是对每种业务指定一个PayWay
,每个service
都只处理这一种类型的业务,获取service
的操作使用的是getBeansOfType(...)
,获取后将这些service
与其对应的PayWay
统一放进一个Map
中(只需加载一次),后面有业务过来了,只要根据PayWay
直接从Map
中获取其处理类进行处理就行了。
使用这种方式的最大好处就是只需根据PayWay
直接获取service
即可,不用遍历所有service
再判断。注意:这种方式适合在判断条件不复杂的情况下使用,如果判断条件较复杂,还是使用上面的方式。
4. 源码分析
接下来我们来分析下spring一些关键方法的源码。
4.1 AbstractBeanFactory#getBean(String)
这个方法是beanFactory
最重要的方法之一,里面包含了bean的整个创建过程(实例化、属性注入、初始化等),关于这个方法,在spring启动流程中已经作了深入分析,想了解的小伙伴可以参考以下文章:
在接下来要分析的两个方法中,我们也会看到它们也会调用该方法来获取bean
。
4.2 DefaultListableBeanFactory#getBeansOfType(Class<T>)
这个方法的作用是获取所有Class
类型的bean
,代码如下:
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
return getBeansOfType(type, true, true);
}
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons,
boolean allowEagerInit) throws BeansException {
// 获取名称
String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
// 获取名称对应的 bean
Map<String, T> result = new LinkedHashMap<>(beanNames.length);
for (String beanName : beanNames) {
try {
// 调用 getBean(String) 方法
Object beanInstance = getBean(beanName);
if (!(beanInstance instanceof NullBean)) {
result.put(beanName, (T) beanInstance);
}
}
catch (BeanCreationException ex) {
...
}
}
return result;
}
复制代码
看到这里,我们就明白了,这个方法的处理操作如下:
- 根据
Class
类型获取所有的beanNames
- 遍历
beanNames
,调用getBean(String)
方法获取对应的bean
- 返回得到的所有
bean
看来,处理关键是beanNames
的获取,也就是DefaultListableBeanFactory#getBeanNamesForType(Class<?>, boolean, boolean)
方法了,一路跟进去,最终到了DefaultListableBeanFactory#doGetBeanNamesForType
,代码如下:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons,
booleanallowEagerInit) {
List<String> result = new ArrayList<>();
// 1. 遍历所有的 beanDefinition 名称
for (String beanName : this.beanDefinitionNames) {
if (!isAlias(beanName)) {
try {
// 2. 得到 beanName 对应的 beanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
// 3. 判断类型是否匹配
// 不是 FactoryBean
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
// 判断类型是否匹配
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (!matchFound) {
// 在 beanName 前加 &
beanName = FACTORY_BEAN_PREFIX + beanName;
// 判断类型是否匹配
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
...
}
}
}
// 手动注册到 beanFactory 中的单例 bean
for (String beanName : this.manualSingletonNames) {
try {
if (isFactoryBean(beanName)) {
// 省略了一些内容
...
// 在 beanName 前加 &
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// 判断匹配
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
...
}
}
return StringUtils.toStringArray(result);
}
复制代码
这个方法的内容比较多,不过逻辑并不复杂,关键部分都给出了注释,这里对流程总结如下:
- 遍历所有的
beanDefinitionNames
- 对每一个
beanName
,得到其对应的beanDefinition
- 判断传入的类型与当前的
beanDefinition
是否匹配,如果匹配,则将beanName
添加到匹配结果中 - 返回匹配的结果
处理匹配的方法为AbstractBeanFactory#isTypeMatch(String, ResolvableType, boolean)
,这个类的逻辑比较复杂,spring 考虑的情况比较多,如懒加载
,factoryBean
,代理对象
等,这里简单提供下这个方法的匹配思路:
- 根据
beanName
从singletonObjects
获取bean的实例,如果实例存在,则进入第2步,否则进行第3步 - 判断得到的bean的实例是否匹配传入的类(调用
ResolvableType#isAssignableFrom(java.lang.Class<?>)
方法判断),如果匹配,则返回true,否则返回false - 根据
beanName
获取对应的BeanDefinition
,判断BeanDefinition
的beanClass
与传入的类型是否匹配(也是调用ResolvableType#isAssignableFrom(java.lang.Class<?>)
方法判断),如果匹配,则返回true,否则返回false
以上就是AbstractBeanFactory#isTypeMatch(String, ResolvableType, boolean)
方法的大致逻辑了,就不深入分析了。
4.3 BeanFactory#getBean(Class<T>)
接下来我们来看看BeanFactory#getBean(Class<T>)
方法:
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
/**
* 进一步调用
*/
@SuppressWarnings("unchecked")
@Override
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 得到结果
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}
复制代码
我们继续进入DefaultListableBeanFactory#resolveBean
:
@Nullable
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args,
boolean nonUniqueAsNull) {
// 这里是关键
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
// 去 父 BeanFactory 查找,不作分析
BeanFactory parent = getParentBeanFactory();
...
return null;
}
复制代码
这一步主要是调用了resolveNamedBean(...)
处理,后面去ParentBeanFactory
的操作,我们不作过多分析。继续进入DefaultListableBeanFactory#resolveNamedBean(ResolvableType, Object[], boolean)
方法:
private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType,
@Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 获取对应类型的bean的所有名称,与 getBeansOfType(Class) 一样的操作
String[] candidateNames = getBeanNamesForType(requiredType);
// 得到的 beanName 数量大于1,需要确实哪个优先级高
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName)
|| getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
// 返回结果只有一个,调用 getBean(String, ...) 获取 bean
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName,
(T) getBean(beanName, requiredType.toClass(), args));
}
// 返回结果有多个
else if (candidateNames.length > 1) {
// 收集起来,全部放到 candidates 中,value 为 bean或对应的Class
Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName,
(beanInstance instanceof NullBean ? null : beanInstance));
}
else {
candidates.put(beanName, getType(beanName));
}
}
// 找到 primary 的bean,可以使用 @Primary 标记
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
// 确定bean的优先级,可以使用 @Order 或实现 Orderd 接口
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
// 调用 getBean(String, ...) 获取 bean
beanInstance = getBean(candidateName, requiredType.toClass(), args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
// 无法确定唯一,抛出异常
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}
复制代码
这个方法里主要调用了getBeanNamesForType(...)
(与getBeansOfType(Class)
方法一样的操作,关于这个方法就不再分析了),如果得到的结果大于1个,则会进行一系列的判断。
对这个方法,流程总结如下:
- 根据类型获取所有满足条件的
beanNames
,获取方式与getBeansOfType(Class)
一样 - 如果得到的
beanNames
只有1个,则调用getBean(String, ...)
获取 bean,然后返回 - 如果得到的
beanNames
有多个,需要进一步确定返回哪个bean,确定方式包含两个方面:@Primary
与优先级 - 处理
@Primary
注解流程如下:- 判断这些
beanNames
对应的Class
标记了@Primary
- 如果有且仅有一个标记了
@Primary
,那么这个就是最终返回的类, - 如果有两个或以上的
Class
标记了@Primary
,则抛出异常 - 如果没有
Class
标记@Primary
,则不处理
- 判断这些
- 优先级的处理方式如下:
- 优先级可以通过
@Order
注解或实现Orderd
接口来指定 - 如果没有指定优先级,则默认使用最低优先级
- 如果存在优级最高的
bean
,则返回该bean
- 优先级可以通过
- 如果最终得到的
bean
还是超过1个,则抛出异常
BeanFactory#getBean(Class<T>)
方法的分析就先到这里了,从源码来看,这个方法会遍历所有的beanDefinitionMap
,且获取时可能会抛异常,如果能确定bean
的名称,建议优先考虑调用AbstractBeanFactory#getBean(String)
方法来获取bean
。
5. 总结
本文主要介绍了beanFactory
的相关内容
beanFactory
定义的基本方法beanFactory
的继承结构- 通过两个实例展示下spring下的策略模式使用
- 最后分析了
beanFactory
两个方法的实现
本文原文链接:my.oschina.net/funcy/blog/… ,限于作者个人水平,文中难免有错误之处,欢迎指正!原创不易,商业转载请联系作者获得授权,非商业转载请注明出处。
本系列的其他文章