简介
说明
本文介绍Spring中的FactoryBean,包括:作用,用法,原理,MyBatis对FactoryBean的应用。
FactoryBean的作用
- 通过一个FactoryBean来生产一个对象
- 可以获取生产出的对象的类型
- 可以判断生产出的对象是不是单例
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
请先
!