在Spring中,有两个很容易混淆的类:BeanFactory和FactoryBean。前者是Factory也就是IOC容器或对象工厂,后者是Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对于FactoryBean而言,这个Bean不是普通的Bean,而是一个能产生或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
两者其实都是Spring提供的接口,如下:
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) 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);
}
BeanFactory 就是我们常说的Spring容器,其内包含着大量的Bean,我们可以从BeanFactory 获取到想要的Bean,或者查询Bean的一些信息。
而FactoryBean则是众多Bean里的一种,只不过这种Bean是一种辅助Bean或者说中间人,它的作用是为你提供另一个或者一些Bean。
FactoryBean
先来看一下FactoryBean的基础用法,简而言之就是实现FactoryBean接口,然后重写其中的getObject方法,如下:
public class ConfigLoaderFactoryBean implements FactoryBean<ConfigLoader> {
private String configLocation;
public void setConfigLocation(String configLocation) {
this.configLocation = configLocation;
}
@Override
public ConfigLoader getObject() throws Exception {
if (configLocation.startsWith("file:")) {
LocalConfigLoader configLoader = new LocalConfigLoader();
configLoader.setFilePath(configLocation.substring(5));
return configLoader;
} else if (configLocation.startsWith("http:")) {
RemoteConfigLoader configLoader = new RemoteConfigLoader();
configLoader.setServerUrl(configLocation);
return configLoader;
} else {
throw new IllegalArgumentException("Unsupported config location: " + configLocation);
}
}
@Override
public Class<?> getObjectType() {
return ConfigLoader.class;
}
}
然后把这个factoryBean放入容器中,可以采用xml或者@Bean等形式注入。
<bean id="configLoader" class="com.example.ConfigLoaderFactoryBean">
<property name="configLocation" value="http://example.com/config.json"/>
</bean
FactoryBean的必要性
FactoryBean其实相当于一个中间人,我们获取它,往往不是需要它本身,而是希望通过它获得另一个Bean,自然的我们会产生疑问,为什么要多此一举?如果我们通过它是为了获得另一个Bean,那么为什么不直接实例化另一个Bean然后放入Spring容器呢?比如在方法上使用@Bean注解。
factoryBean接口的诞生更早,所以早期很多的结构采用了这种方式。后续有了@Bean注解以后,在方法上使用@Bean注解也能实现复杂Bean的创建了。
那是不是所有情况都能使用@Bean来替代factoryBean呢?比如我们想每次获取的Bean都是实时的,又比如我们需要一个计时器Bean,但你注入的Bean都被固定了,只有通过工厂,才能每次获取都能得到一个实时的新Bean。同样的,使用factoryBean还有一个懒加载的作用,对于某些复杂的Bean能在获取时再进行实例化。
BeanFactory
BeanFactory与ApplicationContext
提及BeanFactory,首先我们会想到Spring的重要特性IOC,IOC要求有一个能管理所有Bean的管家,而管家需要一个盛放这些Bean的容器,这个容器就是BeanFactory。
尽管我们在日常项目中,使用的容器是具有更全功能的ApplicationContext,但ApplicationContext也是BeanFactory的子接口,其除了单纯的容器功能外,还有配置元信息,应用事件机制,资源管理等功能,所以我们可以说ApplicationContext是BeanFactory的增强版本。
BeanFactory的使用
在早期的spring项目中,经常会在代码中指定使用某种BeanFactory ,并且使用下面的方式去加载资源。
//读取核心的配置文件
ClassPathResource resource = new ClassPathResource("MyContext.xml");
BeanFactory BeanFactory = new XmlBeanFactory(resource);
顾名思义XmlBeanFactory就是能够读取并解析xml资源,解析出各种Bean后存入自身,而在后期,springboot的大规模使用后,其内置的工厂可以解析xml、properties以及注解等多种配置来源。
当然,其实Spring本身就有相当的自动化程度,比如当我们在启动类上使用。
@ImportResource(location = {"classpath:MyContext.xml"})
它也能导入内容,并根据资源后缀是否为".groovy"判断是使用GroovyBeanDefinitionReader.class 还是 XmlBeanDefinitionReader.class,对资源解析完成后,把Bean定义注册进BeanFactory中。
总结
可以发现:BeanFactory 和 FactoryBean 除了名字相似、都能包含一些Bean实例之外,其实没有什么相同的地方。前者是SpringIOC的核心,是存放一切Bean的容器;后者只不过是对复杂Bean的一种包装,比如我们常用的myBatis组件,针对各个mapper级接口生成的Bean实例,就是以FactoryBean的形式存在Spring容器中的。
标签:String,BeanFactory,Spring,Bean,FactoryBean,throws,name From: https://blog.csdn.net/m0_68642284/article/details/136761704