文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring中这两个对象ObjectFactory与FactoryBean接口你使用过吗?

2024-11-30 08:17

关注

FactoryBean

public interface FactoryBean {
 // 返回真实的对象
 T getObject() throws Exception;
 // 返回对象类型
 Class getObjectType();
 // 是否单例;如果是单例会将其创建的对象缓存到缓存池中。
 boolean isSingleton();
}

该接口就是一个工厂Bean,在获取对象时,先判断当前对象是否是FactoryBean,如果是再根据getObjectType的返回类型判断是否需要的类型,如果匹配则会调用getObject方法返回真实的对象。该接口用来自定义对象的创建。

注意:如果A.class 实现了FactoryBean,如果想获取A本身这个对象则bean的名称必须添加前缀 '&',也就是获取Bean则需要ctx.getBean("&a")

当注入属性是ObjectFactory或者ObjectProvider类型时,系统会直接创建DependencyObjectProvider对象然后进行注入,只有在真正调用getObject方法的时候系统才会根据字段上的泛型类型进行查找注入。

2 实际应用

ObjectFactory在Spring源码中应用的比较多

2.1 创建Bean实例

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
  protected  T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    // other code  
    if (mbd.isSingleton()) {
      //getSingleton方法的第二个参数就是ObjectFactory对象(这里应用了lamda表达式)
      sharedInstance = getSingleton(beanName, () -> {
        try {
          return createBean(beanName, mbd, args);
        } catch (BeansException ex) {
          // Explicitly remove instance from singleton cache: It might have been put there
          // eagerly by the creation process, to allow for circular reference resolution.
          // Also remove any beans that received a temporary reference to the bean.
          destroySingleton(beanName);
          throw ex;
        }
      });
      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    // other code  
  }
}

这里的getSingleton方法就是通过不同的Scope(singleton,prototype,request,session)创建Bean;具体的创建细节都是交个ObjectFactory来完成。

2.2 Servlet API注入

在Controller中注入Request,Response相关对象时也是通过ObjectFactory接口。

容器启动时实例化的上下文对象是AnnotationConfigServletWebServerApplicationContext;

调用在AbstractApplicationContext#refresh.postProcessBeanFactory

public class AnnotationConfigServletWebServerApplicationContext {
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    super.postProcessBeanFactory(beanFactory);
    if (this.basePackages != null && this.basePackages.length > 0) {
      this.scanner.scan(this.basePackages);
    }
    if (!this.annotatedClasses.isEmpty()) {
      this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
    }
  }    
}

super.postProcessBeanFactory(beanFactory)方法进入到ServletWebServerApplicationContext中

public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {
  @Override
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    registerWebApplicationScopes();
  }
  private void registerWebApplicationScopes() {
    ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
    WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
    existingScopes.restore();
  }
}

WebApplicationContextUtils工具类

public abstract class WebApplicationContextUtils {
    
  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
    registerWebApplicationScopes(beanFactory, null);
  }
  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) {
    beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
    beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
    if (sc != null) {
      ServletContextScope appScope = new ServletContextScope(sc);
      beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
      // Register as ServletContext attribute, for ContextCleanupListener to detect it.
      sc.setAttribute(ServletContextScope.class.getName(), appScope);
    }
    beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
    beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
    if (jsfPresent) {
      FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
    }
  }
}

这里的RequestObjectFactory,ResponseObjectFactory,SessionObjectFactory,WebRequestObjectFactory都是ObjectFactory接口。

这几个接口实际获取的对象都是从当前线程的上下文中获取的(通过ThreadLocal),所以在Controller中直接属性注入相应的对象是线程安全的。

注意:这里registerResolvableDependency方法意图就是当有Bean需要注入相应的Request,Response对象时直接注入第二个参数的值即可。

2.3 自定义定义ObjectFactory

在IOC容器,如果有两个相同类型的Bean,这时候在注入的时候肯定是会报错的,示例如下:

public interface AccountDAO {
}
@Component
public class AccountADAO implements AccountDAO {
}
@Component
public class AccountBDAO implements AccountDAO {
}
@RestController
@RequestMapping("/accounts")
public class AccountController {
  @Resource
  private AccountDAO dao ;
}

当我们有如上的Bean后,启动容器会报错如下:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.pack.objectfactory.AccountDAO' available: expected single matching bean but found 2: accountADAO,accountBDAO
  at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220) ~[spring-beans-5.2.13.RELEASE.jar:5.2.13.RELEASE]

期望一个AccountDAO类型的Bean,但当前环境却有两个。

解决这个办法可以通过@Primary和@Qualifier来解决,这两个方法这里不做介绍;接下来我们通过BeanFactory#registerResolvableDependency的方式来解决;

自定义BeanFactoryPostProcessor

// 方式1:直接通过beanFactory获取指定的bean注入。
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    // beanFactory的实例是DefaultListableBeanFactory,该实例内部维护了一个ConcurrentMap resolvableDependencies 的集合,Class作为key。
    beanFactory.registerResolvableDependency(AccountDAO.class, beanFactory.getBean("accountBDAO"));
  }
}

自定义ObjectFactory

public class AccountObjectFactory implements ObjectFactory {
  @Override
  public AccountDAO getObject() throws BeansException {
    return new AccountBDAO() ;
  }
}
// 对应的BeanFactoryPostProcessor
beanFactory.registerResolvableDependency(AccountDAO.class, new AccountObjectFactory());

当一个Bean的属性在填充(注入)时调用AbstractAutowireCapableBeanFactory.populateBean方法时,会在当前的IOC容器中查找符合的Bean,最终执行如下方法:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
  protected Map findAutowireCandidates(@Nullable String beanName, Class requiredType, DependencyDescriptor descriptor) {
    // 从当前IOC容器中查找所有指定类型的Bean  
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
    Map result = new LinkedHashMap<>(candidateNames.length);
    // 遍历DefaultListableBeanFactory对象中通过registerResolvableDependency方法注册的
    for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
      Class autowiringType = classObjectEntry.getKey();
      if (autowiringType.isAssignableFrom(requiredType)) {
        Object autowiringValue = classObjectEntry.getValue();
        // 解析自动装配的类型值(主要就是判断当前的值对象是否是ObjectFactory对象)  
        autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
        if (requiredType.isInstance(autowiringValue)) {
          // 要注意这里,如果通过registerResolvableDependency添加的对象是个ObjectFactory,那么最终会调用factory.getObject方法返回真实的对象并且加入到result集合中。这时候相当于当前类型还是找到了多个Bean还是会报错。
          result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
          break;
        }
      }
    }
    for (String candidate : candidateNames) {
      if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
        addCandidateEntry(result, candidate, descriptor, requiredType);
      }
    }
    return result;
  }    
}
// AutowireUtils.resolveAutowiringValue方法
// 该方法中会判断对象是否是ObjectFactory
public static Object resolveAutowiringValue(Object autowiringValue, Class requiredType) {
  if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
    ObjectFactory factory = (ObjectFactory) autowiringValue;
    if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
      autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(), new Class[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
    } else {
      // 进入这里之间调用getObject返回对象  
      return factory.getObject();
    }
  }
  return autowiringValue;
}

完毕!!!


来源:Spring全家桶实战案例源码内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯