Spring FactoryBean 的常见使用场景总结

简介: FactoryBean 是 Spring 框架中的一个重要接口,用于自定义 Bean 的创建逻辑。常见使用场景包括:1. **复杂 Bean 的创建**:如数据源配置。2. **延迟实例化**:按需创建资源密集型对象。3. **动态代理**:为 Bean 创建 AOP 代理。4. **自定义配置**:根据特定配置创建 Bean。5. **第三方库集成**:利用 FactoryBean 封装外部库的创建过程。

FactoryBean的常见使用场景

1. 复杂Bean的创建

java

代码解读

复制代码

// DataSourceFactory.java
public class DataSourceFactory implements FactoryBean<DataSource> {

    private String url;
    private String username;
    private String password;

    // Setters for url, username, and password

    @Override
    public DataSource getObject() throws Exception {
        // 创建复杂的数据库连接池对象
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        return new HikariDataSource(config);
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// Spring配置文件 (applicationContext.xml)
<bean id="dataSourceFactory" class="com.example.DataSourceFactory">
    <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
    <property name="username" value="root"/>
    <property name="password" value="password"/>
</bean>

<bean id="dataSource" factory-bean="dataSourceFactory" factory-method="getObject"/>

// 测试代码
public class DataSourceFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource) context.getBean("dataSource");
        System.out.println(dataSource);
    }
}

2. 延迟实例化

java

代码解读

复制代码

// ExpensiveResourceFactory.java
public class ExpensiveResourceFactory implements FactoryBean<ExpensiveResource> {

    @Override
    public ExpensiveResource getObject() throws Exception {
        // 创建资源密集型对象
        return new ExpensiveResource();
    }

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

    @Override
    public boolean isSingleton() {
        return false; // 每次调用都会创建一个新的实例
    }
}

// Spring配置文件 (applicationContext.xml)
<bean id="expensiveResource" class="com.example.ExpensiveResourceFactory"/>

// 测试代码
public class ExpensiveResourceFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        ExpensiveResource resource1 = (ExpensiveResource) context.getBean("expensiveResource");
        ExpensiveResource resource2 = (ExpensiveResource) context.getBean("expensiveResource");
        System.out.println(resource1);
        System.out.println(resource2);
        System.out.println(resource1 == resource2); // 应该输出 false
    }
}

3. 动态代理

java

代码解读

复制代码

// ProxyFactoryBean.java
public class ProxyFactoryBean implements FactoryBean<MyService> {

    private MyService target;

    public void setTarget(MyService target) {
        this.target = target;
    }

    @Override
    public MyService getObject() throws Exception {
        // 创建动态代理
        return (MyService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                System.out.println("Before method: " + method.getName());
                Object result = method.invoke(target, args);
                System.out.println("After method: " + method.getName());
                return result;
            }
        );
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// Spring配置文件 (applicationContext.xml)
<bean id="myServiceTarget" class="com.example.MyServiceImpl"/>

<bean id="myServiceProxy" class="com.example.ProxyFactoryBean">
    <property name="target" ref="myServiceTarget"/>
</bean>

// 测试代码
public class ProxyFactoryBeanTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        MyService myService = (MyService) context.getBean("myServiceProxy");
        myService.someMethod();
    }
}

4. 自定义配置

java

代码解读

复制代码

// ConfigurableBeanFactory.java
public class ConfigurableBeanFactory implements FactoryBean<MyBean> {

    private String config;

    public void setConfig(String config) {
        this.config = config;
    }

    @Override
    public MyBean getObject() throws Exception {
        // 根据配置创建Bean
        MyBean myBean = new MyBean();
        myBean.setConfig(config);
        return myBean;
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// Spring配置文件 (applicationContext.xml)
<bean id="configurableBeanFactory" class="com.example.ConfigurableBeanFactory">
    <property name="config" value="someConfigValue"/>
</bean>

<bean id="myBean" factory-bean="configurableBeanFactory" factory-method="getObject"/>

// 测试代码
public class ConfigurableBeanFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        MyBean myBean = (MyBean) context.getBean("myBean");
        System.out.println(myBean.getConfig()); // 应该输出 "someConfigValue"
    }
}

5. 第三方库集成

java

代码解读

复制代码

// ThirdPartyBeanFactory.java
public class ThirdPartyBeanFactory implements FactoryBean<ThirdPartyBean> {

    @Override
    public ThirdPartyBean getObject() throws Exception {
        // 使用第三方库的API创建对象
        return new ThirdPartyBeanBuilder().build();
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// Spring配置文件 (applicationContext.xml)
<bean id="thirdPartyBean" class="com.example.ThirdPartyBeanFactory"/>

// 测试代码
public class ThirdPartyBeanFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        ThirdPartyBean thirdPartyBean = (ThirdPartyBean) context.getBean("thirdPartyBean");
        System.out.println(thirdPartyBean);
    }
}

FactoryBean的实现原理

FactoryBean的实现原理涉及Spring框架的核心机制,包括Bean的定义、创建和管理。FactoryBean接口的核心在于它提供了一种自定义Bean实例化逻辑的方式。以下是FactoryBean的实现原理:

1. FactoryBean接口

FactoryBean接口定义了三个主要方法:

  • T getObject() throws Exception: 返回由这个FactoryBean创建的Bean实例。
  • Class<?> getObjectType(): 返回这个FactoryBean创建的Bean的类型。
  • boolean isSingleton(): 返回这个FactoryBean创建的Bean是否是单例的。

2. Spring容器如何处理FactoryBean

当Spring容器遇到一个实现了FactoryBean接口的Bean定义时,它会执行以下步骤:

  1. 识别FactoryBean:Spring容器会检查Bean定义的类是否实现了FactoryBean接口。如果是,Spring容器会将其识别为一个FactoryBean
  2. 调用getObject()方法:当需要获取这个Bean实例时,Spring容器会调用FactoryBeangetObject()方法,而不是直接实例化这个类。这允许开发者在getObject()方法中自定义Bean的创建逻辑。
  3. 处理单例和原型:根据isSingleton()方法的返回值,Spring容器会决定是缓存这个Bean实例(单例)还是每次都调用getObject()方法来创建新的实例(原型)。
  4. 获取Bean类型:Spring容器会调用getObjectType()方法来确定这个FactoryBean创建的Bean的类型。这在某些情况下(例如,类型检查或自动装配)非常有用。

3. 实现细节

下面是一个简单的FactoryBean实现示例,以及Spring容器如何处理它的示例代码:

java

代码解读

复制代码

public class MyBeanFactory implements FactoryBean<MyBean> {

    @Override
    public MyBean getObject() throws Exception {
        // 自定义Bean的创建逻辑
        return new MyBean();
    }

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

    @Override
    public boolean isSingleton() {
        return true; // 返回true表示这个Bean是单例的
    }
}

4. Spring容器处理流程

假设在Spring配置文件中定义了一个FactoryBean

xml

代码解读

复制代码

<bean id="myBeanFactory" class="com.example.MyBeanFactory"/>

当Spring容器启动时,它会进行以下步骤:

  1. Bean定义解析:Spring容器解析myBeanFactory的Bean定义,并识别它实现了FactoryBean接口。
  2. 实例化FactoryBean:Spring容器实例化MyBeanFactory类。
  3. 调用getObject()方法:当应用程序请求myBeanFactory这个Bean时,Spring容器会调用MyBeanFactorygetObject()方法,而不是直接返回MyBeanFactory实例。
  4. 返回实际BeangetObject()方法返回的MyBean实例被返回给请求者。
  5. 单例处理:如果isSingleton()方法返回true,Spring容器会缓存这个MyBean实例,以便后续请求直接返回缓存的实例。如果返回false,每次请求都会调用getObject()方法创建新的实例。

5. 示例代码

以下是一个完整的示例,包括Spring配置和测试代码:

java

代码解读

复制代码

// MyBean.java
public class MyBean {
    // Bean的属性和方法
}

// MyBeanFactory.java
public class MyBeanFactory implements FactoryBean<MyBean> {

    @Override
    public MyBean getObject() throws Exception {
        // 自定义Bean的创建逻辑
        return new MyBean();
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// Spring配置文件 (applicationContext.xml)
<bean id="myBeanFactory" class="com.example.MyBeanFactory"/>

// 测试代码
public class MyBeanFactoryTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        MyBean myBean = (MyBean) context.getBean("myBeanFactory");
        System.out.println(myBean);
    }
}

通过上述步骤和示例,可以看到FactoryBean的实现原理和Spring容器如何处理FactoryBean。这一机制使得Spring框架在Bean的创建和管理上具有极大的灵活性。


转载来源:https://juejin.cn/post/7373867360020348966

相关文章
|
5月前
|
Java 关系型数据库 MySQL
Spring5深入浅出篇:Spring中的FactoryBean对象
Spring5深入浅出篇:Spring中的FactoryBean对象
|
5月前
|
存储 监控 Java
|
5月前
|
XML Java 数据格式
spring中怎么通过静态工厂和动态工厂获取对象以及怎么通过 FactoryBean 获取对象
spring中怎么通过静态工厂和动态工厂获取对象以及怎么通过 FactoryBean 获取对象
69 0
|
2天前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
5月前
|
Java 数据库连接 API
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
87 0
|
4月前
|
缓存 Java 数据库连接
探究Spring Boot中@PostConstruct注解的使用场景
【6月更文挑战第2天】在Spring Boot开发过程中,了解和合理利用@PostConstruct注解是非常重要的。这个简单却强大的注解能够帮助开发者在依赖注入完成之后执行初始化逻辑,从而确保组件在使用前已经完全准备就绪。
94 4
|
4月前
|
Java Spring
聊聊Spring中两种创建Bean的方式:BeanDefinition.setInstanceSupplier() 和 FactoryBean
聊聊Spring中两种创建Bean的方式:BeanDefinition.setInstanceSupplier() 和 FactoryBean
|
5月前
|
Java API Spring
|
5月前
|
XML Java 数据格式
Spring5源码(8)-BeanFactory和FactoryBean的区别
Spring5源码(8)-BeanFactory和FactoryBean的区别
53 0
|
5月前
|
XML Java 数据格式
③【Spring】整合第三框架的常用机制:FactoryBean
③【Spring】整合第三框架的常用机制:FactoryBean
74 0