Spring之BeanFactory和FactoryBean接口的区别

简介: 总结 Spring框架中的BeanFactory接口和FactoryBean接口因为名称相似,老是容易搞混淆,而且也是面试过程中经常会碰到的一个问题。所以本文就专门给大家整理出来。


文章目录

   一、BeanFactory接口

   二、FactoryBean接口

       1.简单实现

       2.增强实现

       3.FactoryBean的实际使用案例

   三、总结

 Spring框架中的BeanFactory接口和FactoryBean接口因为名称相似,老是容易搞混淆,而且也是面试过程中经常会碰到的一个问题。所以本文就专门给大家整理出来。

一、BeanFactory接口

 BeanFactory接口是Spring容器的核心接口,负责:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

image.png

 Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Object bean =  bf.getBean(IUserService.class);
System.out.println(bean);

接口中定义的方法

public interface BeanFactory {
  String FACTORY_BEAN_PREFIX = "&";
  Object getBean(String name) throws BeansException;
  <T> T getBean(String name, Class<T> requiredType) throws BeansException;
  Object getBean(String name, Object... args) throws BeansException;
  <T> T getBean(Class<T> requiredType) throws BeansException;
  <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
  boolean containsBean(String name);
  boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
  boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
  boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
  boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
  Class<?> getType(String name) throws NoSuchBeanDefinitionException;
  String[] getAliases(String name);
}

二、FactoryBean接口

 BeanFactory接口是Spring的核心接口。功能非常复杂,这个时候如果我们想要编写一些比较复杂点儿的逻辑就会触及到其他一些不必要的接口,不好实现。这时候使用FactoryBean就比较方便了。FactoryBean以Bean结尾是个Bean对象,不是工厂。接口中定义的方法如下:

public interface FactoryBean<T> {
  /**
   * 返回对象的实例
   */
  T getObject() throws Exception;
  /**
   * 返回对象的类型
   */
  Class<?> getObjectType();
  /**
   * 是否是单例
   */
  boolean isSingleton();
}

   17

1.简单实现

接口和实现类

public interface IUserService {
  public void doSome();
}
public class UserServiceImpl implements IUserService {
  public UserServiceImpl(){
    System.out.println("--被实例化了--");
  }
  @Override
  public void doSome() {
    System.out.println("UserServiceImpl 。。。 被执行了");
  }
}

自定义FactoryBean

public class MyFactoryBean implements FactoryBean<IUserService>{
  @Override
  public IUserService getObject() throws Exception {
    System.out.println("--IUserService实例化之前---");
    IUserService service = new UserServiceImpl();
    System.out.println("--IUserService实例化后---");
    return service;
  }
  @Override
  public Class<?> getObjectType() {
    return IUserService.class;
  }
  @Override
  public boolean isSingleton() {
    return true;
  }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="myFactoryBean" class="com.dpb.factorybean.MyFactoryBean"/>
</beans>

测试–通过类型获取

@Test
public void test1() {
  BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
  Object bean =  bf.getBean(IUserService.class);
  System.out.println(bean);
}

输出结果

--IUserService实例化之前---
--被实例化了--
--IUserService实例化后---
com.dpb.service.UserServiceImpl@5315b42e

测试–通过id获取

@Test
public void test1() {
  BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
  Object bean =  bf.getBean("myFactoryBean");
  System.out.println(bean);
}

输出结果

--IUserService实例化之前---
--被实例化了--
--IUserService实例化后---
com.dpb.service.UserServiceImpl@783e6358

如果想要获取FactoryBean对象 id前加 &就可以

@Test
public void test1() {
  BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
  Object bean =  bf.getBean("&myFactoryBean");
  System.out.println(bean);
}

输出结果

com.dpb.factorybean.MyFactoryBean@3b81a1bc

2.增强实现

 通过FactoryBean创建一个代理类来增强目标类,我们来看下效果

接口和实现类

public interface IUserService {
  public void doSome();
}
public class UserServiceImpl implements IUserService {
  public UserServiceImpl(){
    System.out.println("--被实例化了--");
  }
  @Override
  public void doSome() {
    System.out.println("UserServiceImpl 。。。 被执行了");
  }
}

自定义FactoryBean

public class MyFactoryBean implements FactoryBean,InitializingBean,DisposableBean{
  private Object proxyObject;
  private Object target;
  private String interfaceName;
  @Override
  public Object getObject() throws Exception {
    return proxyObject;
  }
  @Override
  public Class<?> getObjectType() {
    return proxyObject.getClass()==null?Object.class:proxyObject.getClass();
  }
  @Override
  public boolean isSingleton() {
    return true;
  }
  /**
   * MyFactoryBean 对象销毁的回调方法
   * @throws Exception
   */
  @Override
  public void destroy() throws Exception {
    System.out.println("destroy ....");
  }
  /**
   * MyFactoryBean 对象实例化的方法
   */
  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("---afterPropertiesSet---");
    proxyObject = Proxy.newProxyInstance(
          this.getClass().getClassLoader()
          , new Class[]{Class.forName(interfaceName)}
          , new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("----代理方法执行开始----");
              Object obj = method.invoke(target, args);
              System.out.println("----代理方法执行结束----");
              return obj;
            }
          });
  }
  public String getInterfaceName() {
    return interfaceName;
  }
  public void setInterfaceName(String interfaceName) {
    this.interfaceName = interfaceName;
  }
  public Object getTarget() {
    return target;
  }
  public void setTarget(Object target) {
    this.target = target;
  }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">
  <!-- 注册目标对象 -->
  <bean class="com.dpb.service.UserServiceImpl" id="userServiceImpl"/>
  <!-- 注册FactoryBean对象 -->
  <bean id="myFactoryBean" class="com.dpb.factorybean.MyFactoryBean">
    <property name="interfaceName" value="com.dpb.service.IUserService"/>
     <property name="target" ref="userServiceImpl"/> 
  </bean>
</beans>

测试

@Test
public void test1() {
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  IUserService bean =   (IUserService) ac.getBean("myFactoryBean");
  System.out.println("****************");
  bean.doSome();
  System.out.println();
}

输出结果:

--被实例化了--
---afterPropertiesSet---
****************
----代理方法执行开始----
UserServiceImpl 。。。 被执行了
----代理方法执行结束----

小结:通过输出结果我们可以看到通过FactoryBean接口我们也可以实现BeanFactory中某些接口提供的功能,而且会更加的灵活一些。

3.FactoryBean的实际使用案例

 Spring在整合mybatis框架的时候提供的SqlSessionFactoryBean就是FactoryBean的很好的实现。

<!-- 整合mybatis -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" 
id="sqlSessionFactoryBean" >
  <!-- 关联数据源 -->
  <property name="dataSource" ref="dataSource"/>
  <!-- 关联mybatis的配置文件 -->
  <property name="configLocation" value="classpath:mybatis-cfg.xml"/>
  <!-- 添加别名设置 -->
  <property name="typeAliasesPackage" value="com.sxt.model"/>
  <!-- 映射文件和接口文件不在同一个目录下的时候,需要单独指定映射文件的路径 -->
  <property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

 Spring会调用SqlSessionFactoryBean这个实现了FactoryBean的工厂Bean 同时加载dataSource,Mapper文件的路径,对sqlSessionFactory进行初始化。

image.png

源代码比较多就不一一贴出来。到了这儿可以自行跟踪下源代码。

核心方法

@Override
  public void afterPropertiesSet() throws Exception {
    // 省略
    this.sqlSessionFactory = buildSqlSessionFactory();
  }
  protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
    Configuration configuration;
    XMLConfigBuilder xmlConfigBuilder = null;
    // 省略
    return this.sqlSessionFactoryBuilder.build(configuration);
  }
/**
  * {@inheritDoc}
  */
 @Override
 public SqlSessionFactory getObject() throws Exception {
   if (this.sqlSessionFactory == null) {
     afterPropertiesSet();
   }
   return this.sqlSessionFactory;
 }
 /**
  * {@inheritDoc}
  */
 @Override
 public Class<? extends SqlSessionFactory> getObjectType() {
   return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
 }
 /**
  * {@inheritDoc}
  */
 @Override
 public boolean isSingleton() {
   return true;
 }

maven坐标:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>1.3.2</version>
</dependency>

三、总结

   BeanFactory是Spring中IOC容器最核心的接口,遵循了IOC容器中所需的基本接口。例如我们很常见的:ApplicationContext,XmlBeanFactory 等等都使用了BeanFactory这个接口。

   FactoryBean是工厂类接口,当你只是想简单的去构造Bean,不希望实现原有大量的方法。它是一个Bean,不过这个Bean能够做为工厂去创建Bean,同时还能修饰对象的生成。

   FactoryBean比BeanFactory在生产Bean的时候灵活,还能修饰对象,带有工厂模式和装饰模式的意思在里面,不过它的存在还是以Bean的形式存在。


相关文章
|
24天前
|
存储 安全 Java
|
1月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
1月前
|
监控 Java 应用服务中间件
Spring和Spring Boot的区别
Spring和Spring Boot的主要区别,包括项目配置、开发模式、项目依赖、内嵌服务器和监控管理等方面,强调Spring Boot基于Spring框架,通过约定优于配置、自动配置和快速启动器等特性,简化了Spring应用的开发和部署过程。
51 19
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
66 2
|
1月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
112 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
1月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
190 0
|
2月前
|
存储 数据采集 Java
Spring Boot 3 实现GZIP压缩优化:显著减少接口流量消耗!
在Web开发过程中,随着应用规模的扩大和用户量的增长,接口流量的消耗成为了一个不容忽视的问题。为了提升应用的性能和用户体验,减少带宽占用,数据压缩成为了一个重要的优化手段。在Spring Boot 3中,通过集成GZIP压缩技术,我们可以显著减少接口流量的消耗,从而优化应用的性能。本文将详细介绍如何在Spring Boot 3中实现GZIP压缩优化。
305 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实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
37 0
|
2月前
|
XML Java 数据格式
Spring BeanFactory深度讲解
Spring `BeanFactory` 是 Spring 容器的基础,负责创建、配置和管理 Bean 实例,并提供对 Bean 生命周期的管理和控制。它通过读取配置文件或注解来实例化和管理 Bean,支持 XML、Java 配置和注解配置方式。与 `ApplicationContext` 相比,`BeanFactory` 更轻量级,采用延迟加载策略,适用于资源受限的环境。它实现了工厂模式,将对象的创建和管理分离,使应用程序更灵活、可扩展且易于维护。