php网站开发课程,如何做网站微信小程序,一建论坛建工教育网,wordpress 输出文章IOC容器的实现
依赖反转#xff1a;
依赖对象的获得被反转了#xff0c;于是依赖反转更名为#xff1a;依赖注入。许多应用都是由两个或者多个类通过彼此的合作来实现业务逻辑的#xff0c;这使得每个对象都需要与其合作的对象的引用#xff0c;如果这个获取过程需要自身…IOC容器的实现
依赖反转
依赖对象的获得被反转了于是依赖反转更名为依赖注入。许多应用都是由两个或者多个类通过彼此的合作来实现业务逻辑的这使得每个对象都需要与其合作的对象的引用如果这个获取过程需要自身实现那么这将导致代码高度耦合并且难以测试。 ----维基百科
依赖控制反转有很多实现方式。在Spring中IOC容器是实现这个模式的载体它可以在对象生成或初始化时直接将数据注入到对象中也可以通过对象引用注入到对象数据域中的方式来注入对方法调用的依赖。这种依赖注入是可以递归的对象被逐层注入。 IOC容器系列的设计与实现BeanFactory 和 ApplicationContext
Spring IOC容器的设计中主要两个主要的容器系列
一个是实现BeanFactory接口的简单容器系列这系列容器只实现了容器的最基本的功能
另一个是ApplicationContext应用上下文他作为容器的高级形态而存在。 具体什么是容器呢它在Spring框架中到底长什么样
其实对IOC容器的使用者来说我们经常接触到的BeanFactory 和 ApplicationContext都可以看成是容器具体表现形式。ApplicationContext是BeanFactory的子接口BeanFactory提供了配置和基本功能ApplicationContext添加了更多企业特定的功能ApplicationContext是BeanFactory的完整超集。在Spring中Spring有各式各样的IOC容器的实现供用户选择和使用。 ApplicationContext接口表示Spring IOC容器负责实例化、配置和组装bean。容器通过读取配置元数据来获取实例化、配置和组装对象的指令。配置元数据用XML、Java注解或Java代码表示。它允许组成应用程序的对象以及这些对象之间丰富的相互依赖关系。 Spring提供了几个ApplicationContext接口的实现。在独立应用程序中通常创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。虽然XML一直是定义配置元数据的传统格式但可以通过提供少量XML配置以声明式地启用对这些附加元数据形式的支持来指示容器使用Java注解或代码作为元数据格式 BeanDefinition
Spring通过BeanDefinition来管理基于Spring的应用中的各种对象以及它们之间的相互依赖关系。BeanDefinition抽象了我们对Bean的定义是让容器起作用的主要数据类型。IOC容器是用来管理对象依赖关系的对IOC容器来说BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象也是容器实现依赖反转功能的核心数据结构依赖反转功能都是围绕对这个BeanDefinition的处理来完成的。 Spring IOC容器的设计 BeanFactory的应用场景
BeanFactory接口定义了IOC容器最基本的形式并且提供了IOC容器所应该遵守的最基本的服务契约。
BeanFactory主要接口
public interface BeanFactory {String FACTORY_BEAN_PREFIX ;Object getBean(String name) throws BeansException;T T getBean(String name, ClassT requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;boolean containsBean(String name);boolean isSingleton(String name) throws NoSuchBeanDefinitionException;boolean isPrototype(String name) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, Class targetType) throwsNoSuchBeanDefinitionException;Class getType(String name) throws NoSuchBeanDefinitionException;String[] getAliases(String name);
}ApplicationContext的应用场景
ApplicationContext是一个高级形态意义的IOC容器ApplicationContext在BeanFactory的基础上添加了很多附加功能。 IOC容器的初始化过程
简单来说IOC容器的初始化是由refresh()方法来启动的。主要包括 resource定位过程 桶装水先找到水 BeanDefinition载入 水处理成合格的水 相当于把定义的BeanDefinition在IOC容器中转化成一个Spring内部表示的数据结构的过程。IOC容器对Bean的管理和依赖注入功能的实现是通过对其持有的BeanDefinition进行各种相关相关操作来完成的。这些BeanDefinition数据在IOC容器中通过一个HashMap来保持和维护。 refresh()方法执行过程 prepareRefresh();
//这里是在子类中启动refreshBeanFactory()的地方
ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);try {//设置BeanFactoy的后置处理postProcessBeanFactory(beanFactory);//调用BeanFactory的后处理器这些后处理器是在Bean定义中向容器注册的invokeBeanFactoryPostProcessors(beanFactory);//注册Bean的后处理器在Bean创建过程中调用。registerBeanPostProcessors(beanFactory);//对上下文中的消息源进行初始化initMessageSource();//初始化上下文中的事件机制initApplicationEventMulticaster();//初始化其他的特殊BeanonRefresh();//检查监听Bean并且将这些Bean向容器注册registerListeners();//实例化所有的(non-lazy-init)单件finishBeanFactoryInitialization(beanFactory);//发布容器事件结束Refresh过程finishRefresh();} catch (BeansException ex) {//为防止Bean资源占用在异常处理中销毁已经在前面过程中生成的单件BeandestroyBeans();}向IOC容器注册这些BeanDefinition 将水装入桶中 将BeanDefinition放入值beanDefinitionMap Map中
org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition总结IOC容器的初始化过程主要是工作是在IOC容器中建立BeanDefinition数据映射 注意Bean定义的载入和依赖注入是两个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器搜索Bean的时候(除了layzinit设置为true设置了lazyinit属性那么这个Bean的依赖注入在IOC容器初始化时就预先完成了无需等待初始化完成后使用getBean去触发)。
补充lazy-init属性的处理其实是直接采用getBean去触发依赖注入。所以说白了与正常依赖注入的出发相比只是触发的时间和场合不同原理是一样的。 IOC容器的依赖注入
一句话getBean是依赖注入的起点之后会调用createBeancreateBean不仅生成了Bean还会对Bean初始化进行处理。比如实现了在BeanDefinition中的init-method属性定义Bean后置处理器等。 主要涉及到方法 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean // 获取Bean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean // 创建Bean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance // 创建Bean实例 提供了两种实例化Java对象方法一种通过使用Java反射功能(BeanUtils.instantiateClass)一种是通过CGLIB生成。 public Object instantiate(RootBeanDefinition bd, Nullable String beanName, BeanFactory owner) {// Dont override the class with CGLIB if no overrides.if (!bd.hasMethodOverrides()) {Constructor? constructorToUse;synchronized (bd.constructorArgumentLock) {constructorToUse (Constructor?) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse null) {final Class? clazz bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, Specified class is an interface);}try {if (System.getSecurityManager() ! null) {constructorToUse AccessController.doPrivileged((PrivilegedExceptionActionConstructor?) clazz::getDeclaredConstructor);}else {constructorToUse clazz.getDeclaredConstructor();}bd.resolvedConstructorOrFactoryMethod constructorToUse;}catch (Throwable ex) {throw new BeanInstantiationException(clazz, No default constructor found, ex);}}}return BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass.return instantiateWithMethodInjection(bd, beanName, owner);}}org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean // 填充Bean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) // Bean的初始化方法调用 通过jdk反射机制得到Method对象然后调用Bean定义中申明的初始化方法 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods 执行Bean初始化方法 如果Bean实现了InitializingBean接口则先执行afterPropertiesSet()方法 执行Bean的init方法(Bean定义的initMethodName) IOC容器中Bean生命周期
Bean实例的创建为Bean实例设置属性调用Bean的初始化方法应用使用BeanBean销毁 FatoryBean的实现
通过org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean方法得知获取Bean核心是factory.getObject()也就说通过实现FactoryBean接口开放getOject方法供使用者自由发挥使用。
private Object doGetObjectFromFactoryBean(FactoryBean? factory, String beanName) throws BeanCreationException {Object object;try {if (System.getSecurityManager() ! null) {AccessControlContext acc getAccessControlContext();try {object AccessController.doPrivileged((PrivilegedExceptionActionObject) factory::getObject, acc);}catch (PrivilegedActionException pae) {throw pae.getException();}}else {object factory.getObject();}}catch (FactoryBeanNotInitializedException ex) {throw new BeanCurrentlyInCreationException(beanName, ex.toString());}catch (Throwable ex) {throw new BeanCreationException(beanName, FactoryBean threw exception on object creation, ex);}// Do not accept a null value for a FactoryBean thats not fully// initialized yet: Many FactoryBeans just return null then.if (object null) {if (isSingletonCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName, FactoryBean which is currently in creation returned null from getObject);}object new NullBean();}return object;}可看出此时getBean是通过getObject()方法获取到的Bean BeanPostProcessor的实现
简称“BPP” BPP是使用IOC容器时经常使用到的一个特性这个Bean的后置处理器是一个监听器可以监听容器触发的事件。将它向IOC容器注册后容器中管理的Bean具备了接收IOC容器事件回调的能力。BPP是一个接口主要只有以下两个方法
public interface BeanPostProcessor {/*** 在Bean的初始化前提供回调入口*/Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}/*** 在Bean的初始化后提供回调入口*/Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) 初始化Bean 如何与IOC结合 autowiring(自动依赖装配)的实现
只有在类变量属性为类此时需要在IOC容器中寻找依赖的对象由此可推出自动依赖装配的过程是在属性填充过程中即populateBean()方法中实现。
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean 在populateBean方法中可找到autowireByName与autowireByType两个方法通过类名/类型进行自动装配
autowireByName通过名称自动注入直接根据属性名getBean()从IOC容器中获取Bean即可。 autowireByType稍微复杂一些但是最终依然是通过getBean从IOC容器中获取Bean。 参考
Spring技术内幕深入解析Spring架构与设计原理第2版