Spring - FactoryBean扩展接口

简介: FactoryBean扩展接口

@[toc]

在这里插入图片描述


Pre

Spring Boot - 扩展接口一览

在这里插入图片描述

org.springframework.beans.factory.FactoryBean


package org.springframework.beans.factory;

import org.springframework.lang.Nullable;


public interface FactoryBean<T> {


    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


    @Nullable
    T getObject() throws Exception;

    
    @Nullable
    Class<?> getObjectType();

    
    default boolean isSingleton() {
        return true;
    }

}

在这里插入图片描述

一般情况下,Spring通过反射机制利用bean的class属性指定支线类去实例化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。

配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。

从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式

在这里插入图片描述


FactoryBean中的设计模式----工厂方法模式

工厂方法模式是简单工厂模式的一种升级或者说是进一步抽象,它可以应用于更加复杂的场景,灵活性也更高。

在简单工厂中,由工厂类进行所有的逻辑判断、实例创建;

如果不想在工厂类中进行判断,可以为不同的产品提供不同的工厂,不同的工厂生产不同的产品,每一个工厂都只对应一个相应的对象,这就是工厂方法模式。

Spring 中的 FactoryBean 就是这种思想的体现,FactoryBean 可以理解为工厂 Bean


public interface FactoryBean<T> {
  T getObject();
  Class<?> getObjectType();
  boolean isSingleton();
}

我们定义一个类 ArtisanFactoryBean 来实现 FactoryBean 接口,主要是在 getObject 方法里 new 一个 Artisan对象。这样我们通过 getBean(id) 获得的是该工厂所产生的 Artisan 的实例,而不是 ArtisanFactoryBean本身的实例,像下面这样:

BeanFactory bf = new ClassPathXmlApplicationContext("artisan.xml");
Artisan  artisanBean = (Artisan) bf.getBean("artisanFactoryBean");

在这里插入图片描述


FactoryBean VS BeanFactory

  • BeanFactory,就是bean的工厂,主要是通过定位、加载、注册以及实例化来维护对象与对象之间的依赖关系,以此来管理bean
  • FactoryBean,bean的一种,顾名思义,它也可以用来生产bean,也实现了相应的工厂方法。
  • 一般来说,Bean是由BeanFactory生产,但FactoryBean的特殊之处就在于它也能生产bean。
  • 获取FactoryBean的方法是getBean("&"+beanName); 就是在beanName加个"&"前缀,若直接getBean(beanName),获取到的是FactoryBean通过getObject接口生成的Bean

源码解析

org.springframework.beans.factory.support.AbstractBeanFactory#getBean
          org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean    
              org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean

我们从 AbstractBeanFactory#doGetBean 梳理起来

 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

        /**
         * 通过name获取BeanName,这里不能使用name作为beanName:
         * 1. name可能是别名,通过方法转换为具体的实例名称
         * 2. name可能会以&开头,表明调用者想获取FactoryBean本身,而非FactoryBean创建bean
         *    FactoryBean 的实现类和其他的 bean 存储方式是一致的,即 <beanName, bean>,
         *    beanName 中是没有 & 这个字符的。所以我们需要将 name 的首字符 & 移除,这样才能从
         *    缓存里取到 FactoryBean 实例。
         *
         */
        final String beanName = transformedBeanName(name);
        Object bean;

        // 从缓存中获取bean
        Object sharedInstance = getSingleton(beanName);

        /*
         * 如果 sharedInstance = null,则说明缓存里没有对应的实例,表明这个实例还没创建。
         *( BeanFactory 并不会在一开始就将所有的单例 bean 实例化好,而是在调用 getBean 获取bean 时再实例化,也就是懒加载)。
         * getBean 方法有很多重载,比如 getBean(String name, Object... args),我们在首次获取
         * 某个 bean 时,可以传入用于初始化 bean 的参数数组(args),BeanFactory 会根据这些参数
         * 去匹配合适的构造方法构造 bean 实例。当然,如果单例 bean 早已创建好,这里的 args 就没有
         * 用了,BeanFactory 不会多次实例化单例 bean。
         */
        if (sharedInstance != null && args == null) {
            // 省略.....

            /*
             * 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
             * sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
             * bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
             * 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
             */
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        /*
         * 如果上面的条件不满足,则表明 sharedInstance 可能为空,此时 beanName 对应的 bean
         * 实例可能还未创建。这里还存在另一种可能,如果当前容器有父容器,beanName 对应的 bean 实例
         * 可能是在父容器中被创建了,所以在创建实例前,需要先去父容器里检查一下。
         */
        else {
            // BeanFactory 不缓存 Prototype 类型的 bean,无法处理该类型 bean 的循环依赖问题
            //判断是否存在循环依赖
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // 如果 sharedInstance = null,则到父容器中查找 bean 实例
            BeanFactory parentBeanFactory = getParentBeanFactory();
            // ......

        
            try {
                // 合并父 BeanDefinition 与子 BeanDefinition
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // 检查是否有 dependsOn 依赖,如果有则先初始化所依赖的 bean
                String[] dependsOn = mbd.getDependsOn();
                // ......
                    
                // 创建 bean 实例
                if (mbd.isSingleton()) {

                    /*
                     * 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过
                     * getSingleton(String, ObjectFactory) 方法获取 bean 实例。
                     * getSingleton(String, ObjectFactory) 方法会在内部调用
                     * ObjectFactory 的 getObject() 方法创建 bean,并会在创建完成后,
                     * 将 bean 放入缓存中。
                     */
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    
                    // 如果 bean 是 FactoryBean 类型,则调用工厂方法获取真正的 bean 实例。否则直接返回 bean 实例
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                // 创建 prototype 类型的 bean 实例
                else if (mbd.isPrototype()) {
                    // ......
                }


                // 创建其他类型的 bean 实例
                else {
                    // ......
        }

        // ......
        return adaptBeanInstance(name, beanInstance, requiredType);
    }

重点来了 getObjectForBeanInstance 。 在getObjectForBeanInstance方法,它主要完成对获取的Bean Instance进行检测是否为FactoryBean,如果是FactoryBean则通过工厂方法获取Bean以及初始化后处理


protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        // 判断name是否为Bean FactoryBean的引用
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            return beanInstance;
        }

        // beanInstance可能是普通的bena或者FactoryBean,如果是普通的Bean直接返回实例
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }
        
        // 如果是FactoryBean,使用FactoryBean来创建一个bean实例
        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        else {
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // Return bean instance from factory.
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            // 从FactoryBean中获取创建的Bean
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

先看看

    public static boolean isFactoryDereference(@Nullable String name) {
        return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
    }

在这里插入图片描述

FactoryBean创建的Bean的名称FactoryBean本身作为一个Bean在Spring容器中是用是否包含 & 前缀来区分的。

继续往下来

// 从FactoryBean中获取创建的Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        // 单例模式
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    // 通过factory.getObject获取
                    object = doGetObjectFromFactoryBean(factory, beanName);
                    
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    }
                    else {
                        if (shouldPostProcess) {
                            if (isSingletonCurrentlyInCreation(beanName)) {
                                // Temporarily return non-post-processed object, not storing it yet..
                                return object;
                            }
                            beforeSingletonCreation(beanName);
                            try {
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", ex);
                            }
                            finally {
                                afterSingletonCreation(beanName);
                            }
                        }
                        if (containsSingleton(beanName)) {
                            //将获取到的对象放到factoryBeanObjectCache单例缓存map进行存储
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }
                return object;
            }
        }
        else {
            // 非单例模式,直接通过factory.getObejct获取,然后再返回给用户
            Object object = doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = postProcessObjectFromFactoryBean(object, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                }
            }
            return object;
        }
    }

通过源码我们可以发现,无论是单例和非单例都会调用doGetObjectFromFactoryBean方法,那毫无疑问就是生成bean对象的方法:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
        Object object;
        try {
            // 系统安全处理器不为空
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    // 也是调用 factory::getObject
                    object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                // 调用FactoryBean的getObject方法
                object = factory.getObject();
            }
        }
        catch (){


        }
        // ....

        return object;
    }

OK , DONE

在这里插入图片描述


扩展示例

package com.artisan.bootspringextend.testextends;

import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/12/5 23:45
 * @mark: show me the code , change the world
 */

@Slf4j
public class ExtendFactoryBean2 {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                .genericBeanDefinition(UserServiceFactoryBean.class);
        definitionBuilder.addPropertyValue("username", "artisan");
        beanFactory.registerBeanDefinition("userService", definitionBuilder.getBeanDefinition());


        UserService userService = (UserService) beanFactory.getBean("userService");
        //artisan
        log.info(userService.getUsername());


        UserServiceFactoryBean userServiceFactoryBean = (UserServiceFactoryBean) beanFactory.getBean("&userService");
        //artisan
        log.info(userServiceFactoryBean.username);
    }

    public static class UserServiceFactoryBean implements FactoryBean<UserService> {

        @Setter
        private String username;


        @Override
        public UserService getObject() {
            UserService userService = new UserService();
            userService.setUsername(username);
            return userService;
        }

        @Override
        public Class<?> getObjectType() {
            return UserService.class;
        }
    }

    @Setter
    @Getter
    public static class UserService {

        private String username;
    }
}
    

定义一个UserServiceFactoryBean,用来生产UserService,将其注册到BeanFactory中,如果使用UserService对象,使用userServiceBean名称,
如果想要获取原来的UserServiceFactoryBean对象,需要使用&userService的Bean名称,&这个前缀是Spring规定的,可以查看BeanFactory#FACTORY_BEAN_PREFIX常量

00:05:24.692 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
00:05:24.762 [main] INFO com.artisan.bootspringextend.testextends.ExtendFactoryBean2 - artisan
00:05:24.762 [main] INFO com.artisan.bootspringextend.testextends.ExtendFactoryBean2 - artisan

Process finished with exit code 0

在这里插入图片描述

相关文章
|
30天前
|
存储 安全 Java
|
1月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
1月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
227 0
|
2月前
|
存储 数据采集 Java
Spring Boot 3 实现GZIP压缩优化:显著减少接口流量消耗!
在Web开发过程中,随着应用规模的扩大和用户量的增长,接口流量的消耗成为了一个不容忽视的问题。为了提升应用的性能和用户体验,减少带宽占用,数据压缩成为了一个重要的优化手段。在Spring Boot 3中,通过集成GZIP压缩技术,我们可以显著减少接口流量的消耗,从而优化应用的性能。本文将详细介绍如何在Spring Boot 3中实现GZIP压缩优化。
339 6
|
1月前
|
XML 缓存 Java
Spring FactoryBean 的常见使用场景总结
FactoryBean 是 Spring 框架中的一个重要接口,用于自定义 Bean 的创建逻辑。常见使用场景包括: 1. **复杂 Bean 的创建**:如数据源配置。 2. **延迟实例化**:按需创建资源密集型对象。 3. **动态代理**:为 Bean 创建 AOP 代理。 4. **自定义配置**:根据特定配置创建 Bean。 5. **第三方库集成**:利用 FactoryBean 封装外部库的创建过程。
|
1月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
40 0
|
3月前
|
JSON 安全 Java
|
3月前
|
存储 SQL Java
|
Java 容器 Spring
Spring FactoryBean浅析
​ Spring容器管理着其内部的Bean,在这些Bean中可能存在着一类特殊的Bean,这一类Bean就是FactoryBean。FactoryBean与其它的Bean不一样的地方在于它既是Bean,也能生产Bean。从容器中获取它和它产生的Bean的方式有些特殊。 #### 源码解析 ##### FactoryBean Spring提供了一个顶级接口FactoryBean用于
2049 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。