所有分类
  • 所有分类
  • 未分类

Spring–FactoryBean–使用/原理/详解

简介

说明

本文介绍Spring中的FactoryBean,包括:作用,用法,原理,MyBatis对FactoryBean的应用。

FactoryBean的作用

  1. 通过一个FactoryBean来生产一个对象
  2. 可以获取生产出的对象的类型
  3. 可以判断生产出的对象是不是单例

FactoryBean的来源

在某些情况下,实例化Bean过程比较复杂,若按照传统的方式,则需要在中提供大量的配置信息,不够灵活,这时采用编码的方式能得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

FactoryBean接口在Spring中占重要地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。

从Spring 3.0 开始, FactoryBean开始支持泛型,即接口声明改为 FactoryBean<T> 的形式。

源码:

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

普通bean与FactoryBean的区别

Spring 容器中有两种bean:普通bean和工厂bean。

普通bean

通过反射来实例化被标记为bean的类。例:@Component指定的类。

FactoryBean

FactoryBean返回的对象不是指定类的一个实例,而是FactoryBean#getObject方法返回的对象。若想获取FactoryBean本身,要在bean的名称添加前缀&来获取FactoryBean对象本身(applicationContext.getBean(“&” + beanName))。

FactoryBean不遵循Spring的生命周期

Spring的作者想要放权给使用者,让使用者自己实现创建一个bean的逻辑,所以Spring并不会过多的插手该Bean的实例化过程,使得一个Bean的实例化完全由使用者本人去实现。

这个类并不会像普通bean那样在Spring容器初始化时进行实例化,而是类似于懒加载,在获取时才进行创建和返回。至于是不是单例,要取决于isSingleton()方法的返回值。

当然,这个创建出来的bean也会被缓存,AOP等逻辑也会对该类生效,当然这都是后话。

简单示例

公共部分

FactoryBean实现类

package com.example.tmp;

import lombok.AllArgsConstructor;
import org.springframework.beans.factory.FactoryBean;

@AllArgsConstructor
public class MyFactoryBean implements FactoryBean {
    private String myBeanName;

    @Override
    public Object getObject() throws Exception {
        MyBean myBean = new MyBean();
        myBean.setName(myBeanName);
        return myBean;
    }

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

bean实体类

package com.example.tmp;

import lombok.Data;

@Data
public class MyBean {
   private Integer id;
   private String name;
}

注册单个FactoryBean

配置类

package com.example.tmp;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {
    @Bean
    public MyFactoryBean getMyBean() {
        return new MyFactoryBean("Tony");
    }
}

controller

package com.example.controller;

import com.example.tmp.MyBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @Autowired
    MyBean myBean;

    @GetMapping("/test1")
    public String test1() {
        System.out.println(myBean.getName());
        return "test1 success";
    }

}

测试

访问:http://localhost:8080/test1

后台结果:

Tony

注册多个FactoryBean

配置类

package com.example.tmp;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {
    @Bean("bean1")
    public MyFactoryBean getMyBean1() {
        return new MyFactoryBean("Tony");
    }

    @Bean("bean2")
    public MyFactoryBean getMyBean2() {
        return new MyFactoryBean("Pepper");
    }
}

controller

package com.example.controller;

import com.example.tmp.MyBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @Autowired
    @Qualifier("bean2")
    MyBean myBean;

    @GetMapping("/test1")
    public String test1() {
        System.out.println(myBean.getName());
        return "test1 success";
    }

}

测试

访问:http://localhost:8080/test1

后台结果:

Pepper

实例分析(MyBatis)

见:Spring–Mybatis源码对FactoryBean的应用 -自学精灵

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录