我们在日常JavaWeb开发中,应该都见过或使用过FactoryBean这个类,很多人估计都没弄懂它和BeanFactory的区别,亦或者是在面试时,可能都会被问到Spring中BeanFactory和FactoryBean的区别。或许我们很多人都没自定义去扩展使用过FactoryBean,但是可以回顾下在哪些框架中有应用到它?例如:Feign的 FeignClientFactoryBean,mybatis-spring的MapperFactoryBean、SqlSessionFactoryBean 等都是扩展实现了Spring的FactoryBean接口,自定义了Bean的创建过程,通过动态代理为Feign接口、Mapper接口生成代理对象,底层屏蔽了很多复杂的Http连接、sql拼接等重复的业务逻辑,我们开发时无需编写实现类。
一般情况下,Spring通过反射机制利用class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在此提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。
FactoryBean 接口定义如下:
public interface FactoryBean {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
// 这个方法,我们可以自定义返回bean实例
@Nullable
T getObject() throws Exception;
// 返回bean类型,可判断传入的class类型是否一致
@Nullable
Class> getObjectType();
// 默认实现:true-单例,flase-原型
default boolean isSingleton() {
return true;
}
}
在进入正题之前,我们先来一点甜点,写一个简单的测试例子,然后再慢慢深入FactoryBean相关的源码,去分析它是如何自定义Bean的创建过程的,因为篇幅有点长,本文先着重分析Class> getObjectType() 方法,下一篇再详细分析getObject()。
定义一个订单相关的service接口
public interface IOrderService {
void saveOrder();
}
service实现类,这里没有添加spring的bean注解:@Service,也无需在xml配置该bean,为了测试如何通过自定义FactoryBean去获取该bean的。
//@Service
public class OrderServiceImpl implements IOrderService {
@Override
public void saveOrder() {
System.out.println("-----创建订单------");
}
}
自定义FactoryBean实现:OrderFactoryBean,记得添加 @Component注解,由spring ioc容器管理此bean (orderFactoryBean)
/**
* @description: 自定义FactoryBean实现
* @author: stwen_gan
* @date:
**/
@Component
public class OrderFactoryBean implements FactoryBean {
/**
* 自定义bean的创建过程
*/
@Override
public Object getObject() throws Exception {
System.out.println("-----调用OrderFactoryBean.getObject----");
// 1、直接new
IOrderService orderService = new OrderServiceImpl();
return orderService;
// 2、通过动态代理,无需实现类,如 Mybatis的xxxMapper接口
// OrderMapper bean = (OrderMapper) Proxy.newProxyInstance(OrderFactoryBean.class.getClassLoader(), new Class[]{OrderMapper.class}, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// // todo
// System.out.println(method.getName());
// return null;
// }
// });
// return bean;
}
/**
* 返回bean的class类型
*/
@Override
public Class> getObjectType() {
return IOrderService.class;
}
/**
* 是否单例,默认单例
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
这里为了方便,getObject()方法中直接new 一个OrderServiceImpl 实现类即可,当然通过动态代理生成代理对象也可以,这里不分析,已注释掉,无需关注,可自行测试。
测试类:
/**
* @description: 测试
* @author: stwen_gan
* @date:
**/
public class FactoryBeanTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext(MyConfig.class);
//测试自定义FactoryBean实现getObject产生bean
IOrderService bean = context.getBean(IOrderService.class);
System.out.println(bean);
System.out.println("---------------------");
System.out.println(context.getBean("orderFactoryBean"));// bean是OrderServiceImpl,并不是OrderFactoryBean
System.out.println(context.getBean("orderFactoryBean"));// 测试是否单例
System.out.println(context.getBean("orderFactoryBean"));// 测试是否单例
}
}
运行输出:
可以发现,获取的bean实例都是同一个,因为上面的 isSingleton方法返回true(单例)。
疑问:
为了弄明白Spring的FactoryBean其中的奥秘,我们就直接从这个getBean方法入手,它是 AbstractApplicationContext 的方法,有很多子类重载了它的方法,如下:
// 根据Class类型获取bean
@Override
public T getBean(Class requiredType) throws BeansException {
// 检查BeanFactory的激活状态
assertBeanFactoryActive();
//getBeanFactory()获取到的是一个DefaultListableBeanFactory的默认实例
return getBeanFactory().getBean(requiredType);
}
// 根据beanName获取bean
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
这里,我们只分析getBean(Class
其中,getBeanFactory()获取到的是一个DefaultListableBeanFactory的默认实例,所以我们需要去DefaultListableBeanFactory中看getBean这个方法的具体实现:
DefaultListableBeanFactory#getBean(Class
@Override
public T getBean(Class requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
@Override
public T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// 根据传入的Class类型、参数等解析bean
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}
在上面的代码中,我们重点关注的是resolveBean这个方法:
@Nullable
private T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
// 解析bean
NamedBeanHolder namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
//如果当前Spring容器获取不到相应的bean信息,则从父容器中获取
//SpringMVC是一个很典型的父子容器
BeanFactory parent = getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
}
else if (parent != null) {
ObjectProvider parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
}
else {
return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
}
}
return null;
}
重点跟进resolveNamedBean方法,如何解析beanName:
@Nullable
private NamedBeanHolder resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
//这个方法是根据传入的Class类型来获取BeanName,因为一个接口可以有多个实现类的情况(多态),
//所以这里返回的是一个String数组,这个过程也比较复杂。
//这里需要注意的是,我们调用getBean方法传入的type为com.example.demo.spring.factorybean.IOrderService类型,但是我们没有在Spring容器中注入IOrderService类型的Bean
//正常来说我们在这里是获取不到beanName的,但是事实是不是这样呢?看下面我们对getBeanNamesForType的分析
String[] candidateNames = getBeanNamesForType(requiredType);
// 如果有多个BeanName,则筛选合适的BeanName
// 自动注入相关的判断
if (candidateNames.length > 1) {
// 自动注入的bean候选者
List autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
// list 转 String 数组,放入候选的beanNames中
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
//如果BeanName只有一个, 我们调用getBean方法来获取Bean实例来放入到NamedBeanHolder中
//这里getBean是根据beanName,bean的Class类型和参数来获取bean
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
else if (candidateNames.length > 1) {
// 将候选bean放入一个map
Map candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
//从单例池中根据beanName获取该bean对象
if (containsSingleton(beanName) && args == null) {
// 根据beanName获取bean
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
//单例池中没有获取到该bean,则通过getType方法继续获取Bean实例
candidates.put(beanName, getType(beanName));
}
}
//有多个Bean实例的话 则取带有Primary注解或者带有Primary信息的Bean
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
//如果没有Primary注解或者Primary相关的信息,则取优先级高的Bean实例
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
// 最终获取到一个合适的beanName后,就可以根据Class类型,继续调用getBean方法获取Bean实例
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType.toClass(), args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
// 如果都没有获取到,则抛异常
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}
在上面的方法中我们传入的type是com.example.demo.spring.factorybean.IOrderService接口类型,但是我们并没有在Spring容器中配置该接口或实现类的bean,那么我们是怎么从getBeanNamesForType获取到beanName的呢?
下面,我们对getBeanNamesForType分析:
@Override
public String[] getBeanNamesForType(ResolvableType type) {
return getBeanNamesForType(type, true, true);
}
@Override
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
Class> resolved = type.resolve();
// type解析不为空
if (resolved != null && !type.hasGenerics()) {
return getBeanNamesForType(resolved, includeNonSingletons, allowEagerInit);
}
else {
return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
}
@Override
public String[] getBeanNamesForType(@Nullable Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
//先从缓存中获取:根据Class类型获取符合的beanNames
Map, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
// 获取到直接返回
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
// 获取不到,则调用doGetBeanNamesForType方法获取符合的beanNames
// 下面会详细分析此方法
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
//判断我们传入的类能不能被当前类加载加载
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
//放入到缓存中,方便下次直接从缓存中获取
//key:IOrderService,Value:orderFactoryBean
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
如下,通过调试与分析发现,cache缓存中,key就是我们传入的com.example.demo.spring.factorybean.IOrderService的Class,value却是我们自定义实现FactoryBean的OrderFactoryBean对应的beanName--orderFactoryBean(我们有给OrderFactoryBean类添加@Component注解,加入到Spring IoC管理),此beanName并非orderService。这也是本文重点,弄懂此问题很关键,它是如何将OrderFactoryBean对应的beanName与IOrderService.class进行关联的?
因此,我们需要分析doGetBeanNamesForType 方法,它是如何通过传入的IOrderService.Class类型却获取到了OrderFactoryBean的beanName:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List result = new ArrayList<>();
// Check all bean definitions.
//循环检查IoC中所有的beanName,这个是在Spring容器启动解析Bean的时候放入到这个List中的
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name
// is not defined as alias for some other bean.
// 只有当bean名称没有定义为其他bean的别名时,才是符合要求的
if (!isAlias(beanName)) {
try {
//根据beanName获取RootBeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
// 这里检查beanDefinition信息的完整性
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// 根据beanName与RootBeanDefinition 判断是否FactoryBean的子类
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 类型、beanName等信息是否匹配
boolean matchFound = false;
boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
// 普通bean(非FactoryBean子类)
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
// FactoryBean 子类
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
// 下面会重点分析此isTypeMatch方法
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
// matchFound=false时
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
//如果不匹配,需要给beanName添加一个统一的前缀&,&beanName 表示这是FactoryBean子类对应的beanName
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
// matchFound=true,则表示符合,添加此beanName到result返回
if (matchFound) {
result.add(beanName);
}
}
}
}
}
// 省略部分无关代码。。。。
return StringUtils.toStringArray(result);
}
在上面的方法中,首先循环遍历Spring中所有的beanNames,根据beanName获取对应的RootBeanDefinition,然后根据我们传入的 ResolvableType type (即 IOrderService.class ),判断是否和当前的beanName相匹配:matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit)。
当遍历到我们的OrderFactoryBean对应的beanName时,发现它是FactoryBean的子类,就会进入else,然后通过isTypeMatch方法判断它是否和我们传入的IOrderService.class相匹配,如下,调试发现是匹配的,即matchFound=true,最终会添加此beanName到result返回:
其中,beanName = FACTORY_BEAN_PREFIX + beanName; (FACTORY_BEAN_PREFIX=“&”),这里当 matchFound=false时,为啥要给FactoryBean子类对应的beanName添加一个前缀&呢?
--> 为了获取FactoryBean子类对象bean本身时,可以传 context.getBean("&orderFactoryBean"),可自行测试,输出:
com.example.demo.spring.factorybean.OrderFactoryBean@1f0f1111
如下是调试的一个小技巧,添加条件断点:
所以下面我们将分析isTypeMatch方法,它是怎么进行类型匹配判断的,如何将OrderFactoryBean对应的beanName与IOrderService进行关联?
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException {
//转换beanName,这里只探讨beanName为orderFactoryBean时isTypeMatch返回的结果
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
//这里是用AbstractApplicationContext的子类来从Spring容器中获取Bean,
//获取beanName为orderFactoryBean的Bean实例 (IoC是可以获取到的,因为我们有在OrderFactoryBean类上添加@Component注解)
Object beanInstance = getSingleton(beanName, false);// beanName:orderFactoryBean-->OrderFactoryBean
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
//判断获取到的OrderFactoryBean是否是FactoryBean的实例
if (beanInstance instanceof FactoryBean) {
//这里判断beanName是不是以&开头,这里明显不是(“orderFactoryBean”),这里可以想一下什么情况下会有&开头的Bean,上面也有说明
if (!isFactoryDereference) {
//这里就是从OrderFactoryBean实例中获取type类型,下面会分析一下这个方法
Class> type = getTypeForFactoryBean((FactoryBean>) beanInstance);
//从OrderFactoryBean中获取到的type类型和我们传入的类型是不是同一种类型,是则直接返回true
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isInstance(beanInstance);
}
}
// 省略。。。
其中,Object beanInstance = getSingleton(beanName, false),从Spring容器中获取对应的bean,这里可以思考一个问题:
使用AbstractApplicationContext的子类从Spring容器中获取Bean和使用BeanFactory的子类从容器中获取Bean有什么区别?
前者获取的是beanName对应的bean实例本身(orderFactoryBean:OrderFactoryBean),后者获取到的是我们BeanFactory子类中自定义getObject()方法返回的实例对象(即 orderFactoryBean:OrderServiceImpl)。
下面,接着分析 getTypeForFactoryBean
@Nullable
protected Class> getTypeForFactoryBean(final FactoryBean> factoryBean) {
try {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction>)
factoryBean::getObjectType, getAccessControlContext());
}
else {
//看到这是不是很熟悉了,实际调用FactoryBean实例的getObjectType()方法
return factoryBean.getObjectType();
}
}
// 省略。。。
}
通过上面的层层分析,终于发现调用了我们自定义的OrderFactoryBean的getObjectType方法,获取到的值为:com.example.demo.spring.factorybean.IOrderService,和我们传入的type是一样的类型。所以这里返回true,根据我们的分析:如果isTypeMatch返回true的话,我们返回的beanName为orderFactoryBean。因此,我们终于明了:我们调用 context.getBean(IOrderService.class),却将OrderFactoryBean对应的beanName与IOrderService进行关联了。
我们并没有将IOrderService/OrderServiceImpl 配置成Spring bean,即在Spring容器中没有它们对应的BeanDefinition,按理通过IOrderService.class是获取不到对应的bean的,但是我们却自定义了一个工厂Bean(OrderFactoryBean)和IOrderService这个类型有关联,如下:
我们在通过 IOrderService bean = context.getBean(IOrderService.class) 根据type获取bean时,底层Spring会先去获取对应的beanName:
先循环Spring容器中所有的beanNames,然后根据beanName获取对应的BeanDefinition,如果当前bean是FactoryBean的类型,则会从Spring容器中根据beanName获取对应的Bean实例,接着调用获取到的Bean实例的getObjectType方法获取到Class类型,判断此Class类型和我们传入的Class是否是同一类型。如果是则返回此beanName,对应到我们例子就是:根据orderFactoryBean获取到OrderFactoryBean实例,调用OrderFactoryBean的getObjectType方法获取到返回值IOrderService.class。和我们传入的类型一致,所以这里获取的beanName为orderFactoryBean。换句话说这里我们把orderFactoryBean这个beanName映射为了:IOrderService类型,即IOrderService类型对应的beanName为orderFactoryBean。通过本文弄懂了Factory三个方法中的getObjectType的作用,下一篇文章将分析:getBean(String name, Class requiredType, Object… args)这个方法,FactoryBean最终是如何返回我们自定义的bean的。
最后,我画了一个简单版的FactoryBean流程图,描述了我们传入的class类型(IOrderService.calss)与我们自定义的FactoryBean子类之间如何关联起来的,即我们调用getBean(IOrderService.class),底层最终会调用factoryBean.getObjectType(),方便我们从整体上理清脉络(可点击放大图片):
参考:https://blog.csdn.net/zknxx/article/details/79572387
●史上最强Tomcat8性能优化
●阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路
●B2B电商平台--ChinaPay银联电子支付功能
●学会Zookeeper分布式锁,让面试官对你刮目相看
●SpringCloud电商秒杀微服务-Redisson分布式锁方案
查看更多好文,进入公众号--撩我--往期精彩
一只 有深度 有灵魂 的公众号0.0