日积月累,水滴石穿 😄
DefaultListableBeanFactory
上篇就使用到了 DefaultListableBeanFactory
类中的registerBeanDefinition
方法将 BeanDefinition
缓存在了 beanDefinitionMap
Map中。DefaultListableBeanFactory
是Spring中最为核心的 BeanFactory
。先来看一下它的继承关系图。
看到这个图可能会吓一大跳,DefaultListableBeanFactory
实现了这么多接口,不过这也代表着它拥有很多功能,我们先来分析每个接口的作用吧!
-
- AliasRegistry:支持别名功能,一个
beanName
可以对应多个别名
- AliasRegistry:支持别名功能,一个
-
- BeanDefinitionRegistry:可以注册、保存、移除、获取某个
BeanDefinition
- BeanDefinitionRegistry:可以注册、保存、移除、获取某个
-
- SimpleAliasRegistry:它是一个类,实现了
AliasRegistry
接口中所定义的功能,支持别名功能,使用 map 作为 alias 的缓存
- SimpleAliasRegistry:它是一个类,实现了
-
- SingletonBeanRegistry:可以直接注册、获取某个单例 Bean
-
- BeanFactory:Bean工厂,可以根据某个 bean 的名字、或类型、或别名获取某个 Bean 对象
-
- ListableBeanFactory:在
BeanFactory
的基础上,增加了其他功能,可以获取所有BeanDefinition
的beanNames
,可以根据某个类型获取对应的beanNames
,可以根据某个类型获取{类型:对应的Bean}
的映射关系
- ListableBeanFactory:在
-
- HierarchicalBeanFactory:在
BeanFactory
的基础上,添加了获取父BeanFactory
的功能
- HierarchicalBeanFactory:在
-
- DefaultSingletonBeanRegistry:它是一个类,实现了
SingletonBeanRegistry
接口,拥有了直接注册、获取某个单例Bean的功能,还继承了SimpleAliasRegistry
,支持别名功能
- DefaultSingletonBeanRegistry:它是一个类,实现了
-
- ConfigurableBeanFactory:在
HierarchicalBeanFactory
和SingletonBeanRegistry
的基础上,添加了设置父BeanFactory
、类加载器(表示可以指定某个类加载器进行类的加载)、设置SpringEL
表达式解析器(表示该BeanFactory
可以解析EL表达式)、设置类型转化服务(表示该`BeanFactory
可以进行类型转化)、可以添加BeanPostProcessor
(表示该BeanFactory
支持Bean的后置处理器),可以合并BeanDefinition
,可以销毁某个 Bean 等功能
- ConfigurableBeanFactory:在
-
- FactoryBeanRegistrySupport:支持了
FactoryBean
的功能
- FactoryBeanRegistrySupport:支持了
-
- AutowireCapableBeanFactory:直接继承了
BeanFactory
,在BeanFactory
的基础上,支持在创建Bean 的过程中能对 Bean 进行自动装配
- AutowireCapableBeanFactory:直接继承了
-
- AbstractBeanFactory:实现了
ConfigurableBeanFactory
接口,继承了FactoryBeanRegistrySupport
,这个BeanFactory
的功能已经很全面了,但是不能自动装配和获取beanNames
- AbstractBeanFactory:实现了
-
- ConfigurableListableBeanFactory:继承了
ListableBeanFactory
、AutowireCapableBeanFactory
、ConfigurableBeanFactory
- ConfigurableListableBeanFactory:继承了
-
- AbstractAutowireCapableBeanFactory:继承了
AbstractBeanFactory
,实现了AutowireCapableBeanFactory
,拥有了自动装配的功能
- AbstractAutowireCapableBeanFactory:继承了
-
- DefaultListableBeanFactory:继承了
AbstractAutowireCapableBeanFactory
,实现了ConfigurableListableBeanFactory
接口和BeanDefinitionRegistry
接口,所以DefaultListableBeanFactory
的功能很强大
- DefaultListableBeanFactory:继承了
-
- XmlBeanFactory:
XmlBeanFactory
类继承自DefaultListableBeanFacotry
类,使用了自定义的XML 读取器XmlBeanDefinitionReader
,主要使用reader 属性
对资源文件进行读取和注册
- XmlBeanFactory:
通过以上分析,我们可以知道,通过DefaultListableBeanFactory
我们可以做很多事情,比如:
public static void main(String[] args) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 注册BeanDefinition
factory.registerBeanDefinition("user", beanDefinition);
// 注册别名
factory.registerAlias("user", "user1");
// 添加BeanPostProcessor
factory.addBeanPostProcessor(new GongjBeanPostProcessor());
// 获取别名获取Bean对象
System.out.println(factory.getBean("user1"));
// 根据类型获取beanNames
String[] beanNamesForType = factory.getBeanNamesForType(User.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
}
- GongjBeanPostProcessor
public class GongjBeanPostProcessor implements BeanPostProcessor {
//bean初始化方法调用前被调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean初始化方法调用前被调用");
return null;
}
//bean初始化方法调用后被调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean初始化方法调用后被调用");
return null;
}
}
BeanPostProcessor
是 Spring IOC
容器给我们提供的一个扩展接口,该接口就不在本文中阐述。
容器概览
Spring 中的 Ioc 容器,我们可以大致上分为两种:
- BeanFactory
- ApplicationContext
BeanFactory
BeanFactory
是最最基础的 IoC 容器,它提供了一个 IoC 容器所需的基本功能。BeanFactory
默认采用延迟初始化策略,即当容器启动时,并未完成 Bean 的初始化,只有当调用到该 Bean 的实例时,才会完成其初始化操作,并进行依赖注入。
如下代码:
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory.getBean(User.class);
当第一行代码执行的时候,beans.xml
中配置的 User 对象并未进行初始化,只有当第二行 getBean 方法调用时,User 对象才进行了初始化操作。
这样设计的好处是容器启动速度快,因为要做的事情比较少。接下来看看BeanFactory
的示例:
public interface BeanFactory {
//FactoryBean的前缀
//有&符号:返回工厂本身
//无&符号:返回工厂创建的实例
String FACTORY_BEAN_PREFIX = "&";
//返回指定bean的一个实例,如果没有找到指定bean,该方法会抛出异常
Object getBean(String name) throws BeansException;
//返回以给定名称注册的bean实例,并转换为给定class类型
//如果没有找到指定bean、或者类型转换失败,该方法会抛出异常
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
// 通过name获取Bean, 通过第二个参数可以给对象赋值,这种方式需要 指定Bean的作用域为 prototype
Object getBean(String name, Object... args) throws BeansException;
// 根据指定Class类型查找Bean
// 如果没有找到指定bean、或者找到多个类型,该方法会抛出异常
<T> T getBean(Class<T> requiredType) throws BeansException;
//通过类型查找Bean,通过第二个参数可以给对象赋值,需要 指定Bean的作用域为 prototype
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 获取bean的提供者
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
// 是否包含指定名字的bean
boolean containsBean(String name);
// 指定名称的bean是否为单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 指定名称的bean是否为原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 指定名称的bean是否和指定的类型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
// 获取指定名字的bean的类型
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//获取指定名字的bean的类型,如果该 Bean 的类型为 FactoryBean,第二个参数就有作用,当 参数值为 false 时,FactoryBean不会被创建。
@Nullable
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
// 获取指定名字的bean的所有别名
String[] getAliases(String name);
}
实例
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("spring-config.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
//获取别名获取Bean对象
System.out.println("person1 = " + factory.getBean("person"));
System.out.println("person2 = " +factory.getBean("person", Person.class));
System.out.println("person3 = " + factory.getBean("person", "gongj", "shanghai"));
System.out.println("person4 = " + factory.getBean(Person.class));
System.out.println("person4 = " + factory.getBean(Person.class,"gognj"));
System.out.println("getBeanProvider = " + factory.getBeanProvider(Person.class));
System.out.println("containsBean = " + factory.containsBean("person"));
System.out.println("isSingleton = " + factory.isSingleton("person"));
System.out.println("isPrototype = " + factory.isPrototype("person"));
System.out.println("isPrototype = " + factory.isTypeMatch("person",Person.class));
System.out.println("getType = " + factory.getType("person",false));
System.out.println("getType = " + factory.getType("p",false));
String[] people = factory.getAliases("person");
for (String s : people) {
System.out.println("getAliases = " + s);
}
// 根据类型获取beanNames
String[] beanNamesForType = factory.getBeanNamesForType(User.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
}
- xml
<bean id="person" class="com.gongj.bean.Person" scope="prototype"></bean>
<alias name="person" alias="person2"/>
<bean id="p" class="com.gongj.bean.PersonFactory"></bean>
- Person
public class Person {
private String name;
private String address;
public Person(String name, String address) {
this.name = name;
this.address = address;
}
public Person(String name) {
this.name = name;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
- PersonFactory
public class PersonFactory implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
ApplicationContext
ApplicationContext
是在 BeanFactory
的基础上实现的,BeanFactory
的功能它都有,算是一种高级容器。ApplicationContext
在 BeanFactory
的基础上提供了事件发布、国际化等功能。同时,ApplicationContext
和 BeanFactory
还有一个很大的不同。在于 ApplicationContext
在容器启动时,就会完成所有单例非懒加载
Bean 的初始化,这也就以为着容器启动时间较长,并且对系统资源要求也较高。
如下一段代码:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
当这段代码执行时,beans.xml
中配置的 User 对象就会完成初始化。ApplicationContext
是个接口,可以把它理解为一个特殊的BeanFactory
,通常建议比BeanFactory
优先 。
- ApplicationContext 不等于
BeanFactory
,ApplicationContex
t 只是继承了BeanFactory
, 拥有了Bean 工厂的功能,同时,ApplicationContext
还继承了其他接口,比如: - HierarchicalBeanFactory:拥有获取父
BeanFactory
的功能 - ListableBeanFactory:拥有获取
beanNames
的功能 - ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
- MessageSource:拥有国际化功能
ApplicationContext
还有两个比较重要的实现类:
- AnnotationConfigApplicationContext
- ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
- ConfigurableApplicationContext:继承了
ApplicationContext
接口,增加了添加事件监听器、添加 BeanFactoryPostProcessor、设置Environment
,获取ConfigurableListableBeanFactory
等功能 - AbstractApplicationContext:实现了
ConfigurableApplicationContext
接口,继承DefaultResourceLoader
类 - GenericApplicationContext:继承了
AbstractApplicationContext
,实现了BeanDefinitionRegistry
接口,拥有了所有ApplicationContext
的功能,并且可以注册BeanDefinition
,注意这个类中有一个属性是(DefaultListableBeanFactory beanFactory
) - AnnotationConfigRegistry:可以单独注册某个类为
BeanDefinition
(可以处理该类上的@Configuration注解,可以处理@Bean注解)。 - AnnotationConfigApplicationContext:继承了
GenericApplicationContext
,实现了AnnotationConfigRegistry
接口,拥有了以上所有的功能
ClassPathXmlApplicationContext
它也是继承了AbstractApplicationContext
,但是相对于AnnotationConfigApplicationContext
而言,功能没有AnnotationConfigApplicationContext
强大,比如不能注册 BeanDefinition
。