先说结论:
BeanFactory: 是 IOC 容器,并且提供方法支持外部程序对这些 bean 的访问,在程序启动时 根据传入的参数产生各种类型的 bean,并添加到 IOC容器(实现 BeanFactory 接口的类) 的 singletonObject 属性中。
FactoryBean: 首先是个 bean,也存放在 BeanFactory 中。它具有工厂方法的功能,在程序运行中 产生指定(一种)类型的 bean,并添加到了 IOC容器中的 factoryBeanObjectCache 属性中。
BeanFactory是Spring提供的存放Bean的工厂,FactoryBean是一个可生产Bean的工厂Bean
FactoryBean和BeanFactory都是spring的一个类工厂,BeanFactory只能生产一种类型的类,FactoryBean可以生产两种类型的类,一种跟BeanFactory类似,生产的是当前对象,另一种是通过getObject()返回的对象。
一、BeanFactory
先来说说BeanFactory,这个其实是所有Spring Bean的容器根接口。这是Spring bean容器的基本客户端视图。原来是获取Spring Bean的接口,也就是IoC容器。然后我们看类图
1、定义方法:
-
getBean(String name): Spring容器中获取对应Bean对象的方法,如存在,则返回该对象
-
containsBean(String name):Spring容器中是否存在该对象
-
isSingleton(String
name):通过beanName是否为单例对象 isPrototype(String name):判断bean对象是否为多例对象 -
isTypeMatch(String name, ResolvableType
typeToMatch):判断name值获取出来的bean与typeToMath是否匹配 -
getType(String name):获取Bean的Class类型
-
getAliases(String name):获取name所对应的所有的别名
2、主要的实现类(包括抽象类):
- AbstractBeanFactory:抽象Bean工厂,绝大部分的实现类,都是继承于他
- DefaultListableBeanFactory:Spring默认的工厂类
- XmlBeanFactory:前期使用XML配置用的比较多的时候用的Bean工厂
- AbstractXmlApplicationContext:抽象应用容器上下文对象
- ClassPathXmlApplicationContext:XML解析上下文对象,用户创建Bean对象我们早期写Spring的时候用的就是他
3、使用方式:
使用ClassPathXmlApplicationContext读取对应的xml文件实例对应上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
BeanFactory factory = (BeanFactory) context;
4、BeanFactory的使用场景:
- 通过 名字或类型从容器中获取 bean。
- 判断容器中是否包含指定的 bean。
- 判断 bean 是不是单例。
二、FactoryBean
1、FactoryBean的源码:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
//自定义创建bean方式
@Nullable
T getObject() throws Exception;
// 从 beanFactory 中获取bean的类型。
@Nullable
Class<?> getObjectType();
//默认单例
default boolean isSingleton() {
return true;
}
}
2、如何使用FactoryBean
@Service
public class MyFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
//手动创建bean
return new PersonServiceImpl();
}
@Override
public Class<?> getObjectType() {
return PersonServiceImpl.class;
}
//这个方法可以不用覆写,父类默认是单例,如果想设置成非单例可以覆写方法返回false
public boolean isSingleton() {
return false;
}
}
创建PersonServiceImpl类,这里我们没有使用@Service注解,说明应用启动时不会放入IOS容器中
public class PersonServiceImpl implements PersonService{
public void test() {
System.out.println("3333333");
}
}
@SpringBootTest
class DemoApplicationTests {
@Autowired
ApplicationContext applicationContext;
@Test
void test() {
PersonService bean = applicationContext.getBean(PersonService.class);
System.out.println(bean);
bean.test();
PersonService bean2 = applicationContext.getBean(PersonService.class);
System.out.println(bean2);
}
}
编写测试类通过applicationContext的getBean()方法从容器中获取PersonService的bean,发现可以获取到,说明获取bean时发现容器中存在FactoryBean 的实现类MyFactoryBean 并判断传入的类型是否是PersonService如果一样,则返回getObject()方法对象。 这里我们调用了两次bean是不一样的,说明我们设置成了非单例模式
3、FactoryBean的使用场景:
说了这么说,为什么需要 FactoryBean ,它的特殊功能是什么呢?
Spring 中 FactoryBean 最大的应用场景是用在 AOP 中。我们都知道,AOP 实际上是 Spring 在运行是创建出来的代理对象,这个对象是在运行时才被创建的,而不是在启动时定义的,这与工厂方法模式是一致的。更生动地说,AOP 代理对象通过 java 反射机制在运行时创建代理对象,并根据业务需求将相应的方法编织到代理对象的目标方法中。Spring 中的 ProxyFactoryBean 就是干这事的。
因此,FactoryBean 提供了更灵活的实例化 bean 的方法。通过 FactoryBean 我们可以创建更复杂的 bean。