前言
前面已经讲述了很多Spring容器启动、解析、依赖注入等等源码层面的东西了,但是小伙伴有没有一种感觉就是:Spring的设计者把面向对象使用到了极致(使用得非常的好),并且它吧职责单一原则也是使用到了极致。
它各个功能区块,通过接口都进行隔离得很开,这是让Spring能组件化开发,可插拔,变得如此优秀、普适的重要原因。
它的IOC和AOP主要围绕两大阵营展开的,也就是咱们今天的主题:BeanFactory体系和ApplicationContext体系,里面接口众多、抽象实现也众多,因此到了这个节点,我们是时候去宏观的看看这两大阵营的内容了。
Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)
Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)
Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)
BeanFactory和ApplicationContext 区别
基本区别
BeanFactory:BeanFacotry是Spring中最原始的Factory,里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。它没有AOP功能、Web应用功能等等
ApplicationContext:应用上下文,继承BeanFactory接口(因而提供BeanFactory所有的功能),ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承。它是Spring的一各更高级的容器,提供了更多的有用的功能:
- 国际化(MessageSource)(ApplicationContext.getMessage()拿到国际化消息)
- 访问资源,如URL和文件(ResourceLoader) (ApplicationContext acxt =new ClassPathXmlApplicationContext("/applicationContext.xml");能直接读取文件内容)
- 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
- 消息发送、响应机制(ApplicationEventPublisher)
- AOP(拦截器)
相同点:BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册
两者装载bean的区别
BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;(它只去加载Bean的定义信息,显示调用getBean()才会真正去实例化),这样懒加载的优点是:启动快,启动时占用资源少,但具有第一次惩罚的特点
ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化(所有的单例、非懒加载的Bean都会容器启动时候立马实例化);
立马加载好的优点有(缺点你懂的,这里不提了):
1、启动时都初始化完成了,所以运行时会更快。
2、我们就能在系统启动的时候,尽早的发现系统中的配置问题 (因为启动时就得实例化处理)
3、可以(建议)把费时的操作放到系统启动中完成(比如初始化本地缓存、获取连接池的链接等等操作)
BeanFactory体系
先贴一张BeanFactory的继承图表,直观展示该家族的成员们
现在把这些接口分层级,进行逐一说明。
这个里给结论:只要 context 上下文未关闭,ContextRefreshedEvent事件可以多次触发刷新动作, 某些ApplicationContext支持”热”刷新。
比如,XmlWebApplicationContext 支持热刷新, GenericApplicationContext就不支持。
简单的说AbstractRefreshableApplicationContext都支持热刷新(所以它命名为Refreshable嘛),而GenericApplicationContext以及它的子类都是不能支持热舒心的
一级接口:BeanFactory(IOC的始祖)
只有一个,那就是BeanFactory,它提供如下基本方法:
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; //@since 4.1 // 包含Bean定义或者包含单例Bean实例,都会返回true(不管这个Bean是具体的还是抽象的、lazy的还是eager的,in scope or not 都会返回true) boolean containsBean(String name); // 若是单例,getBean()每次都会返回同一个实例 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; //@since 4.2 // 名称为name的Bean的类型,是否和给定的类型匹配(4.2新增的重载接口,传的是ResolvableType ,更加强大了) boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException; // name对应的Bean的类型 Class<?> getType(String name) throws NoSuchBeanDefinitionException; // name对应的Bean的别名们(通过别名也可以依赖注入哦~~~) 通过alia别名,也可以getBean() String[] getAliases(String name); }
这10来个方法,很明显,这是一个典型的工厂模式的工厂接口。
需要注意的是,Spring5.1之后在此接口上又加入了如下两个接口:根据类型获取一个provider
// 返回指定bean的提供程序(Provider),允许延迟(这是重点)按需检索实例,包括可用性和唯一性选项 // @since 5.1 <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType); // @since 5.1 <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
二级接口:HierarchicalBeanFactory、ListableBeanFactory、AutowireCapableBeanFactory
3个子接口,进行了一定功能上的增强
HierarchicalBeanFactory:分层的Bean工厂
提供父容器的访问功能.至于父容器的设置,需要找三级接口ConfigurableBeanFactory的setParentBeanFactory(接口把设置跟获取给拆开了,这是为何呢?Spring早期设计的Bug?).
public interface HierarchicalBeanFactory extends BeanFactory { //返回本Bean工厂的父工厂(至于父工厂怎么设置进去的,却放在了三级接口(个人感觉是Spring的Bug哈哈)) //这个方法实现了工厂的分层 @Nullable BeanFactory getParentBeanFactory(); //本地工厂是否包含这个Bean(忽略其他所有父工厂)。这也是分层思想的体现。 boolean containsLocalBean(String name); }
ListableBeanFactory:可将Bean逐一列出的工厂
它提供了提供容器中bean迭代的功能,不再需要一个个bean地查找.比如可以一次获取全部的bean(太暴力了),根据类型获取bean等等。它的这个功能在Spirng内部有大量的应用。
选哟注意的是:如果同时实现了HierarchicalBeanFactory,返回值不会考虑父类BeanFactory,只考虑当前factory定义的类.当然也可以使用BeanFactoryUtils辅助类来查找祖先工厂中的类。除了getBeanNamesOfType和getBeansOfType这两个方法,其余方法的逻辑都不会考虑父容器的Bean,只会考虑本容器自己的Bean
注意:getBeanDefinitionCount和containsBeanDefinition的实现方法因为效率比较低,还是频繁使用为好.
public interface ListableBeanFactory extends BeanFactory { // 这三个都是和Bean定义信息有关的方法 boolean containsBeanDefinition(String beanName); int getBeanDefinitionCount(); String[] getBeanDefinitionNames(); //返回匹配给定类型(包括子类)的所有bean的名字,如果是普通bean,则是bean定义的名字,如果是 FactoryBean,则是其getObjectType方法返回的对象的名字 // 这个方法只考虑最顶层的bean(top-level beans),内部嵌套的bean(nested beans)即便可能匹配指定的类型也不考虑(不支持内部类) // 在许多实现中,此方法返回的结果与调用getBeansOfType(type, true, true)一样 // 这个方法返回的bean名称应该尽可能与后台配置的bean定义顺序一样 // 此方法只会 // 若没有符合条件的,返回的空数组,而不是null @since 4.2 String[] getBeanNamesForType(ResolvableType type); // 同上 String[] getBeanNamesForType(@Nullable Class<?> type); // includeNonSingletons:false表示只查单例Bean。true表示包含prototype或者其它Scope的Bean们 // allowEagerInit:主要是解决FactoryBean的情况。若为false,只会去检查FactoryBean本身,若为true,FactoryBean本身和它的产生的对象都会被检查匹配 // 上面的方法底层调用的为:return getBeanNamesForType(type, true, true); 所以上面方法是全拿(一般不建议调用) String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit); //返回匹配给定类型(包含子类)的实例,可能是通过bean定义创建,也可以是FactoryBean时其getObjectType返回(注意:此处返回的是实例了,不再是Bean定义了) //此方法仅考虑最顶层bean,不含其内部嵌套的bean,即使内部嵌套的bean匹配给定类型 //此方法返回的结果与调用getBeansOfType(type, true, true)一样 // 实现者:Map的顺序要尽最大可能的与配置时一样 // 备注:此方法但凡一调用,即使有些Bean只是Bean定义的话,也会被立马初始化的~~~~~ <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException; <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException; // 这个接口会把所有标注有指定注解的Bean的定义信息的BeanName返回 //@since 4.0 String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType); // 返回的实例~~~~ Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException; //查找指定bean的指定类型的注解。 // 注意:如果本类没找到,还会去它的接口、它的父类里面找,这个厉害了我的哥 // getBeanNamesForAnnotation依赖于此接口 @Nullable <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException; }
正如这个工厂接口的名字所示,这个工厂接口最大的特点就是可以列出工厂可以生产的所有实例。
这个工厂作为二级接口,有多个个独有的方法,扩展了跟BeanDefinition的功能,提供了BeanDefinition、BeanName、注解有关的各种操作
AutowireCapableBeanFactory:自动装配的Bean工厂
(该接口特别重要,扩展出来的方法也非常的多)对于想要拥有自动装配能力,并且想把这种能力暴露给外部应用的BeanFactory类需要实现此接口。
正常情况下,不要使用此接口,应该更倾向于使用BeanFactory或者ListableBeanFactory接口。此接口主要是针对框架之外,没有向Spring托管Bean的应用。通过暴露此功能,Spring框架之外的程序,具有自动装配等Spring的功能。
需要注意的是,ApplicationContext接口并没有实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext的getAutowireCapableBeanFactory方法,来获取此接口的实例。
另外,如果一个类实现了此接口,那么很大程度上它还需要实现BeanFactoryAware接口。它可以在应用上下文中返回BeanFactory
public interface AutowireCapableBeanFactory extends BeanFactory { // 用于标识外部自动装配功能是否可用。但是此标识不影响正常的(基于注解的等)自动装配功能的使用 int AUTOWIRE_NO = 0; // 不注入 int AUTOWIRE_BY_NAME = 1; // 根据名称注入 int AUTOWIRE_BY_TYPE = 2; // 根据类型注入 int AUTOWIRE_CONSTRUCTOR = 3; // 根据构造器注入 @Deprecated int AUTOWIRE_AUTODETECT = 4; // 标识自动识别一种装配策略来实现自动装配(Spring3.0后废弃) //创建一个给定Class的实例。它会处理各种带有注解的域和方法,并且会调用所有Bean初始化时所需要调用的回调函数 //它会执行所有的关于Bean生命周期的接口方法如BeanPostProcessor //此方法并不意味着by-name或者by-type方式的自动装配,如果需要使用这写功能,可以使用其下面的重载方法 <T> T createBean(Class<T> beanClass) throws BeansException; // 和上面的区别为:创建这个Bean的时候可以指定autowireMode,然后可以把它需要注入的Bean都注入进来(这个Mode会放在Bean定义里,在依赖注入的时候会有用) // Bean定义的默认值为:autowireMode = AUTOWIRE_NO;显然是不会开启自动装配的 // 在populateBean()给属性赋值(依赖注入的时候,会使用到此模式) Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException; //通过调用给定Bean的after-instantiation及post-processing接口,对bean进行装配值 // 此方法主要是用于处理Bean中带有注解的字段和方法。 // 此方法并不意味着by-name或者by-type方式的自动装配,如果需要使用这些功能,可以使用其重载方法autowireBeanProperties // 只会调用populateBean void autowireBean(Object existingBean) throws BeansException; //通过指定的自动装配策略来初始化一个Bean 注意:他会创建一个新的Bean //需要注意的是:此方法不会调用Bean上注册的诸如BeanPostProcessors的回调方法 // 只会调用populateBean Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException; //通过指定的自动装配方式来对给定的已经存在的Bean进行自动装配 //不过会调用指定Bean注册的BeanPostProcessors等回调函数来初始化Bean。 //如果指定装配方式为AUTOWIRE_NO的话,不会自动装配属性,但是,但是,但是依然会调用BeanPiostProcesser等回调方法。 //只会调用populateBean void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException; //配置参数中指定的bean,包括自动装配其域,对其应用如setBeanName功能的回调函数。并且会调用其所有注册的post processor. // beanName表示在Bean定义中的名称。 // populateBean和initializeBean都会被调用 Object configureBean(Object existingBean, String beanName) throws BeansException; //简单的说,就是把Bean定义信息里面的一些东西,赋值到已经存在的Bean里面 // 除了InstantiationAwareBeanPostProcessor的回调方法外,此方法不会在Bean上应用其它的例如BeanPostProcessors void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException; // 实例化这个Bean,会调用所有的postProcessors 方法 Object initializeBean(Object existingBean, String beanName) throws BeansException; //调用参数中指定Bean的postProcessBeforeInitialization/postProcessorsAfterInitialization方法 初始化之前、之后 Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException; Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException; //销毁参数中指定的Bean,同时调用此Bean上的DisposableBean和DestructionAwareBeanPostProcessors方法 //在销毁途中,任何的异常情况都只应该被直接捕获和记录,而不应该向外抛出。 void destroyBean(Object existingBean); //查找唯一符合指定类的实例,如果有,则返回实例的名字和实例本身 //底层依赖于:BeanFactory中的getBean(Class)方法 <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException; //解析出在Factory中与指定Bean有指定依赖关系的Bean(@Autowired依赖注入的核心方法) @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException; //descriptor 依赖描述 (field/method/constructor) //requestingBeanName 依赖描述所属的Bean //autowiredBeanNames 与指定Bean有依赖关系的Bean //typeConverter 用以转换数组和连表的转换器 //备注:结果可能为null,毕竟容器中可能不存在这个依赖嘛~~~~~~~~~~~~~~~~ @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException; }
一共8个跟自动装配有关的方法,实在是繁杂,2个执行BeanPostProcessors的方法,2个分解指定依赖的方法(依赖注入)
从宏观上看,AutowireCapableBeanFactory提供了如下能力:
- 为已经实例化的对象装配属性,这些属性对象都是Spring管理的;
- 实例化一个类型,并自动装配,这些属性对象都是Spring管理的,实例化的类可以不被Spring管理(这点特别重要)。所以这个接口提供功能就是自动装配bean相关的,具体实现方式,其实我们在之前的getBean()解析时候已经有了,请参考:【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析
此接口主要是针对框架之外,没有向Spring托管Bean的应用。通过暴露此功能,Spring框架之外的程序,y也能具有自动装配的能力(此接口赋予它的)。
可以使用这个接口集成其它框架。捆绑并填充(注入)并不由Spring管理生命周期并已存在的实例.像集成WebWork的Actions 和Tapestry Page就很实用
一般应用开发者不会使用这个接口,所以像ApplicationContext这样的外观实现类不会实现这个接口
为了更深入的了解本接口的使用,请参照我专门写的一篇博文,脱离Spring容器来实现依赖注入(脱离容器):
【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)