美文网首页Spring
Spring | 0.9 IoC

Spring | 0.9 IoC

作者: 不一样的卡梅利多 | 来源:发表于2020-05-12 16:50 被阅读0次

    IoC Beans部分

    核心需求 :依据配置信息创建对象和将对象连接起来。

    核心类

    Ioc 容器类定义.png

    各个类职责:
    BeanFactory:获取bean,是bean 容器,接口
    ListableBeanFactory: 查询beanFactory 注册的bean信息,接口
    AbstractBeanFactory:依据bean 注册信息,创建bean 和完成bean 依赖关系组装。核心实现
    ListableBeanFactoryImpl: 完成bean 配置信息注册的具体实现
    XmlBeanFactory : 从配置文件中完成bean配置(定义)信息的注册,还包括xml 文件具体解析

    使用

    配置xml 文件并从容器中获取bean。

    BeanFactory  factory =new XMLBeanFactory(xmlfile)
    Object bean =factory.getBean(“beanName”)
    

    实现

    1、new XMLBeanFactory(xmlfile) 流程

        public XmlBeanFactory(Document doc, BeanFactory parentBeanFactory) throws BeansException {
            super(parentBeanFactory);
            loadBeanDefinitions(doc);
        }
    

    loadBeanDefinitions :
    1、完成xml 文件解析
    2、将xml 配置文件解析成AbstractBeanDefinition 对象
    3、将AbstractBeanDefinition 注册到容器中

    XMLBeanFactory 职责是比较单一的,完成xml文件读取,然后将xml 文件转换成AbstractBeanDefinition 对象,并且将对象注册到容器中。注册的具体实现由父类完成。

    2、factory.getBean(“beanName”) 实现在AbstractBeanFactory 中
    getBeanInternal

    private Object getBeanInternal(String name, Map newlyCreatedBeans) {
    AbstractBeanDefinition bd = getBeanDefinition(transformedBeanName(name));
    return bd.isSingleton() ? 
    getSharedInstance(name, newlyCreatedBeans) :
     createBean(name, newlyCreatedBeans);   
    }
    

    getSharedInstance:
    如果bean实现FactoryBean 接口,生成bean使用自定义工厂方法创建。会创建二次bean,1次创建FactoryBean ,2 次依据FactoryBean 在创建自定bean,这是后续集成AOP 的一个基础

    createBean(name, newlyCreatedBeans);
    if (beanInstance instanceof FactoryBean) {
    FactoryBean factory = (FactoryBean) beanInstance;
    beanInstance = factory.getObject();
    
    // 设置bean 的属性值,可能是配置的静态值,有可能是引用值
    if (factory.getPropertyValues() != null) {
                        logger.debug("Applying pass-through properties to bean with name '" + name + "'");
                        new BeanWrapperImpl(beanInstance).setPropertyValues(factory.getPropertyValues());
                    }
    }
    

    核心逻辑createBean

    private Object createBean(String name, Map newlyCreatedBeans) throws BeansException {
            if (newlyCreatedBeans == null) {
                newlyCreatedBeans = new HashMap();
            }
            Object bean = getBeanWrapperForNewInstance(name, newlyCreatedBeans).getWrappedInstance();
            callLifecycleMethodsIfNecessary(bean, name);
            return bean;
        }
    
    private void callLifecycleMethodsIfNecessary(Object bean, String name) throws BeansException {
            if (bean instanceof InitializingBean) { 
                    ((InitializingBean) bean).afterPropertiesSet();
            }
            if (bean instanceof Lifecycle) {
                    ((Lifecycle) bean).setBeanFactory(this);
                
            }
        }
    
    

    1、创建bean 并且给设置属性值
    2、callLifecycleMethodsIfNecessary 扩展点。bean 实现了xxx 接口,会在bean 创建好后调用 bean 的扩展接口。

    private BeanWrapper getBeanWrapperForNewInstance(String name, Map newlyCreatedBeans) throws BeansException {
                   // 获取bean 定义
            AbstractBeanDefinition bd = getBeanDefinition(name);
    
            BeanWrapper instanceWrapper = null;
            if (bd instanceof RootBeanDefinition) {
            RootBeanDefinition rbd = (RootBeanDefinition) bd;           instanceWrapper=rbd.getBeanWrapperForNewInstance();
            }
            else if (bd instanceof ChildBeanDefinition) {
                ChildBeanDefinition ibd = (ChildBeanDefinition) bd;
                instanceWrapper = getBeanWrapperForNewInstance(ibd.getParentName(), newlyCreatedBeans);
            }
        
            newlyCreatedBeans.put(name, instanceWrapper.getWrappedInstance());
            PropertyValues pvs = bd.getPropertyValues();
    // 设置bean 的属性以及依赖值,引用值处理resolveValueIfNecessary()
            applyPropertyValues(instanceWrapper, pvs, name, newlyCreatedBeans);
            return instanceWrapper;
        }
    

    小结:
    可以看到第一版的bean 容器实现还是很简单的,但是实现和核心的功能,后续的版本都是以此为基础。类结构和名称(BeanFactory)很多一直延续至今。也可以看到最初的设计是非常稳定的。

    IoC Context 部分

    beans 实现了核心的需求,从配置到获取bean。但是我们作为应用开发,还需要集成应用程序部分。用 Context 来装饰BeanFactory ,对BeanFactroy 的功能加强 。从这个设计思路,我们还可以看到后续的Spring boot 项目也是类似的实现方式。用Application 来装饰 Context,加强Context 的功能。

    核心类

    Context 类.png

    1、AbstractApplicationContext 是连接应用与bean 的核心实现类,并且设计了很多抽象方法供子类自定义实现。比如如何获取是创建BeanFactroy 留给子类实现。
    2、AbstractXmlApplicationContext :负责创建XMLFactroy
    3、FileSystemXmlApplicationContext :主要负责配置文件位置定义。

    使用

    自动完成bean 的创建工作,不用beanFactory.get()

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlfile)
    

    源码

    new ClassPathXmlApplicationContext(xmlfile)
    1、指定配置文件在classpath 下面。按照输入流读取到xml 配置文件

    protected InputStream getResourceByPath(String path) throws IOException {
            if (!path.startsWith("/")) {
                // always use root,
                // as loading relative to this class' package doesn't make sense
                path = "/" + path;
            }
            return getClass().getResourceAsStream(path);
        }
    

    2、创建context ,调用 核心 refresh() 方法

    public FileSystemXmlApplicationContext(String[] locations)
            throws ApplicationContextException, IOException {
                    ApplicationContext parent=createParentContext(parentLocations);
                setParent(parent);
            
            // initialize this context
            refresh();
        }
    

    3、AbstractApplicationContext#refresh

        public final void refresh() throws ApplicationContextException {
            refreshBeanFactory();
            configureAllManagedObjects();
            refreshListeners();
            loadOptions();
            onRefresh();
            publishEvent(new ContextRefreshedEvent(this));
        }
    

    refreshBeanFactory : 留给子类实现,AbstractXmlApplicationContext 默认实现为创建XMLBeanFactory。
    configureAllManagedObjects :默认创建所容器中所有bean,所以客户端在使用前,bean 都已经创建好了。

    private void configureAllManagedObjects() throws ApplicationContextException {
        
            String[] beanNames = getBeanDefinitionNames();
    
            for (int i = 0; i < beanNames.length; i++) {
                String beanName = beanNames[i];
                if (isSingleton(beanName)) {
                    try {
                        Object bean = getBeanFactory().getBean(beanName);
                        configureManagedObject(bean);
            
                }
            }
        }
    

    bean 扩展点,如果实现了ApplicationContextAware 接口,创建bean 完成后,会调用该方法

    protected void configureManagedObject(Object o) throws ApplicationContextException {
            if (o instanceof ApplicationContextAware) {
                aca.setApplicationContext(this);
            }
        }
    

    refreshListeners :bean 如果实现了ApplicationListener 接口,将是一个特殊的bean,会接受到ApplicationEvent 事件,也就是最后一步
    publishEvent(ContextRefreshedEvent)

        private void refreshListeners() throws ApplicationContextException {
            String[] listenerNames = getBeanDefinitionNames(ApplicationListener.class);
            for (int i = 0; i < listenerNames.length; i++) {
                String beanName = listenerNames[i];
                try {
                    Object bean = getBeanFactory().getBean(beanName);
                    ApplicationListener l = (ApplicationListener) bean;
                    addListener(l);
            }
        }
    

    onRefresh : 留给子类实现,比如在后续版本中,onRefresh 改方法实现了启动tomcat 服务器。
    publishEvent: 给实现ApplicationListener 接口的bean 发布广播通知。

    小结:
    Context 集成 BeanFactory ,并且默认完成所有bean 的创建工作 ,还提供了应用的一些扩展点 比如 ApplicationListener,ApplicationContextAware。Spring 的扩展方式1:通过实现父类预留的接口,2、通过实现预定的接口。这两种方式都有代码入侵性,不是很友好。但是这种扩展方式的思想一种沿用至今,虽然目前的spring 版本代码有较大的改动,但是核心的部分还是未改变。通过最基础的版本代码阅读,更容易理解核心实现和核心思路。在实现自定义功能时候,我们容易知道什么地方有扩展点。

    我们使用spring 框架一般是使用ApplicationContext,很少单独使用BeanFactory,所以就重点回顾下ApplicationContext 的执行流程。

    1. ApplicationContext 的创建过程 核心逻辑都实现在AbstractApplicationContext#refresh 中

    2. ApplicationContext 预览了很多抽象方法给子类配置使用,单都是非核心的配置功能,比如
      如何获取BeanFactory,如何制定配置文件位置,如何添加默认实现的bean 注册到BeanFactory中

    3. 重点流程还AbstractApplicationContext#refresh
      1、 refreshBeanFactory:获取并且创建 BeanFactory,创建BeanFactory的同时完成bean 配置的注册
      2、configureAllManagedObjects :实例化BeanFactory 中所有的配置的bean。

    2.1 创建bean,更bean 设置属性值
    2.2 如果bean实现了FactoryBean ,那么还会以及FactoryBean.getObjecct() 创建bean
    2.3 创建bean 完成后 会判断bean 有没有实现InitializingBean,Lifecycle 接口
    如果bean 实现了这些接口还会调用((InitializingBean) bean).afterPropertiesSet();
    ((Lifecycle) bean).setBeanFactory(this);
    2.4 如果bean 实现了ApplicationContextAware 接口还会调用setApplicationContext方法
    2.1 ~2.3 的扩展接口(FactoryBean,InitializingBean,Lifecycle)是在beans 定义的
    2.4 的扩展接口(ApplicationContextAware)是在Context 模块中定义的

    1. refreshListeners :获取BeanFactory 所有实现ApplicationListener 接口的bean 。
    2. onRefresh hook 给子类实现
    3. publishEvent,将Context 完成

    Spring 专题

    相关文章

      网友评论

        本文标题:Spring | 0.9 IoC

        本文链接:https://www.haomeiwen.com/subject/nhwbnhtx.html