美文网首页
FactoryBean

FactoryBean

作者: 何德何能者 | 来源:发表于2020-12-17 17:02 被阅读0次

FactoryBean是spring框架定义的一个接口. 用于自定义bean的整个实例化过程;

说到实例化,默认spring bean只有给beanFactory注册beanDefinition就可以自动完成实例化, 这种方式能满足绝大多数的实例化需求. FactoryBean是为了满足复杂实例化的需求,比如aop生成代理对象, 自定义接口给接口生成代理对象等。


image.png

用法.

AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
// 定义beanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserComponentFactoryBean.class);
// 自动注入
builder.setAutowireMode(2);
annotationConfigApplicationContext.registerBeanDefinition("userComponentFactoryBean", builder.getBeanDefinition());
annotationConfigApplicationContext.refresh();
public class UserComponentFactoryBean implements FactoryBean<UserComponent> {
   private UserComponent userComponent;
   @Override
    public UserComponent getObject() throws Exception {
      if (userComponent == null) {
        userComponent = new UserComponent();
        System.out.println("------------ factoryBean----" + userComponent.hashCode());
       }       
       return userComponent;
    }
    @Override
    public Class<?> getObjectType() {
        return UserComponent.class;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
}

这里使用注册beanDefinition的方式让beanFactory感知到有FactoryBean,当然也可以用包扫描的方式加@Component。
这里UserComponentFactoryBean的getObject()方法获取对象实例只是示范,并不规范。
注意:如果UserCompontFactoryBean有依赖其他bean,FactoryBean不会自动完成注入。
如果需要获取bean关联的FactoryBean需要在beanName前加上 &

ProxyFactoryBean

spring中使用ProxyFactoryBean创建代理。
ProxyFactoryBean可以配置的属性有.

  • proxyTargetClass: 如果要对类进行代理,这个属性设置为true
  • optimize: 针对CGLIB优化.
  • frozen: 冻结配置。如果为true有俩个作用,一个是不允许CGLIB优化, 另一个是代理创建后不允许手动进行增强的添加修改。默认是false, 所以一般情况下可以进行增强的手动添加修改;
  • exposeProxy:是否暴露代理对象。如果是true, 则在增强点/目标对象可以通过AopContext.currentProxy()拿到代理对象;
  • proxyInterfaces: string对象数组, 用于指定代理对象实现的接口。如果有值且-proxyTargetClass=false将启用jdk代理.
  • interceptoreNames: 数组, 声明增强点集合。可以用* 一次匹配多个增强点;
  • singleton: ProxyFactoryBean的getObject方法是否返回单例;

示例

  • 定义被代理对象
public class TargetBean {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object getProxy() {
        // 在被代理对象里获取 代理
        return AopContext.currentProxy();
    }
    @Override
    public String toString() {
        return "TargetBean{" +
                "name='" + name + '\'' +
                '}';
    }
}
  • 定义ProxyFactoryBean, 并设置一个增强点
@Configuration
public class FactoryBeanConfig {

    @Bean("debugInterceptor")
    public DebugInterceptor getInterceptor() {
        return new DebugInterceptor();
    }

    @Bean
    public ProxyFactoryBean getProxyFactoryBean() {
        ProxyFactoryBean pfb = new ProxyFactoryBean();
        pfb.setInterceptorNames("debugInterceptor");
        pfb.setTarget(new TargetBean());
        // 暴露代理对象
        pfb.setExposeProxy(true);
        return pfb;
    }
}
  • 启动
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.scan("com.xie.java.aop.factorybean");
        applicationContext.refresh();

        TargetBean targetBean = applicationContext.getBean(TargetBean.class);
        System.out.println("target bean :" + targetBean);
        System.out.println("proxy bean :" + targetBean.getProxy());
        // 任何代理对象都可以强制转换成 Advised对象
        Advised advised = (Advised) targetBean;
        System.out.println("advised :" + advised);
         for (Advisor ad : advised.getAdvisors()) {
             System.out.println("ad :" + ad );
             System.out.println(" count = " + ((DebugInterceptor) ad.getAdvice()).getCount());
          // 如果frozen = false, 可动态添加修改增强点
         }

以上示例可以看出, ProxyFactoryBean是spring bean对象,目标类TargetBean不能是spring bean, 不然 getBean(TargetBean.class)会报异常。
getBean(TargetBean.class)查找ProxyFactoryBean的流程如下
1、根据类型TargetBean.class 查询spring容器中的所有bean Definition; 如果是FactoryBean则触发getType方法。
代码来自 DefaultListableBeanFactory

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
        List<String> result = new ArrayList<String>();

        // Check all bean definitions.
        for (String beanName : this.beanDefinitionNames) {
            // Only consider bean as eligible if the bean name
            // is not defined as alias for some other bean.
            if (!isAlias(beanName)) {
                try {
                    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    // Only check bean definition if it is complete.
                    if (!mbd.isAbstract() && (allowEagerInit ||
                            (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
                                    !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                        // In case of FactoryBean, match object created by FactoryBean.
                                     // 判断bean Definition是否是FactoryBean类型
                        boolean isFactoryBean = isFactoryBean(beanName, mbd);
                        BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
                        boolean matchFound =
                                (allowEagerInit || !isFactoryBean ||
                                        (dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
                                (includeNonSingletons ||
                                        (dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
                                isTypeMatch(beanName, type);
                        if (!matchFound && isFactoryBean) {
                            // In case of FactoryBean, try to match FactoryBean instance itself next.
                            beanName = FACTORY_BEAN_PREFIX + beanName;
                            matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
                        }
                        if (matchFound) {
                            result.add(beanName);
                        }
                    }
                }
                ..... 此处省略

        // Check manually registered singletons too.
              // 检查手动注册的单例
        for (String beanName : this.manualSingletonNames) {
            try {
                // In case of FactoryBean, match object created by FactoryBean.
                        // 又一个FactoryBean判断
                if (isFactoryBean(beanName)) {
                    if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
                        result.add(beanName);
                        // Match found for this bean: do not match FactoryBean itself anymore.
                        continue;
                    }
                    // In case of FactoryBean, try to match FactoryBean itself next.
                    beanName = FACTORY_BEAN_PREFIX + beanName;
                }
                // Match raw bean instance (might be raw FactoryBean).
                if (isTypeMatch(beanName, type)) {
                    result.add(beanName);
                }
            }
            ... 此处省略
        }

        return StringUtils.toStringArray(result);
    }

2、 找到ProxyFactoryBean后, 根据ProxyFactoryBean的 bean name 触发getBean(name, type args)
找到ProxyFactoryBean的实例后 触发getObjectForBeanInstance方法,从bean里获取bean
代码来着 AbstractBeanFactory

/**
     * Get the object for the given bean instance, either the bean
     * instance itself or its created object in case of a FactoryBean.
     * @param beanInstance the shared bean instance
     * @param name name that may include factory dereference prefix
     * @param beanName the canonical bean name
     * @param mbd the merged bean definition
     * @return the object to expose for the bean
     */
    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }

        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd == null) {
        // 此处 触发从FactoryBean 缓存 获取 对象
            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 获取对象
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

3、触发ProxyFactory的 getObject()方法

public Object getObject() throws BeansException {
        initializeAdvisorChain();
        if (isSingleton()) {
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }

总结ProxyFactoryBean到目标代理对象的流程。
1、spring根据getBean的目标类型查找BeanDefinition
2、如果BeanDefinition是FactoryBean,则触发其getType方法
3、拿到ProxyFactoryBean bean后, 最终触发FactoryBean的getObject方法拿到代理对象.

MyBatise在FactoryBean上的应用

MapperFactoryBean<T>

程序急需要定义Mapper接口,MapperFactoryBean就会为其生成代理对象.

Dubbo在FactoryBean上的应用

ReferenceBean<T>

dubbo会为标识为@Reference的注入使用javassist生成具体的bean.

Spring Context在FactoryBean上的应用

ScopedProxyFactoryBean

给声明了@RefreshScope的类生成代理, 处理配置实时刷新同步的问题

相关文章

网友评论

      本文标题:FactoryBean

      本文链接:https://www.haomeiwen.com/subject/demzgktx.html