文档章节

Spring IOC容器的理解

z
 zhaoxp0909
发布于 2017/06/02 15:46
字数 1465
阅读 26
收藏 1
点赞 0
评论 0

Spring是当下主流的开发框架,一个轻量级的DIAOP容器框架,核心思想是IOC和AOP,也是面试中是必问题,开发人员不可不知道,最近和很多面试官交流发现,很多人仅仅是简单知道几个概念,或者大概了解下(我也是这样,时间一长忘了),还是老话好:好记性不如烂笔头。

如何理解IOC

   我的理解是:程序之间的关系由容器管理,组件对象之间的使用关系由主动变成被动,不再直接相互依赖,也就是说组件对象的所有权交给了外部容器管理,使用时通过外部容器获取对象,控制权的转移也就是所谓反转了。目前主流的IOC实现有Spring,EJB,piconcontainer等。

 意义何在?

   在这里不能不说一种软件工程思想——DIP(依赖倒转原则)   

依赖倒置原则
A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

   IOC是DIP的很好体现。解决软件各层之间的解耦,降低了业务对象替换的复杂性,更容易提高开发效率, 

  实现 

    到这里,还要理解对象是如何交由IOC容器管理呢,又如何从IOC容器中获得对象——其实就是所谓的DI和Service Locator,DI就是所谓的依赖注入,  Service Locator就是我们如何从容器中获得对象。

  DI的实现目前有三种方式:

1、使用构造函数
2、属性注入
3、接口注入

 从容器中获得对象,一般我们通过给要使用服务对象指定特定的别名通过工厂模式读取。

spring中依赖注入和Service Locator

使用ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext进行实例化,

1. ApplicationContext fileApplicationContext = new FileSystemXmlApplicationContext( "D:/workSpace/springDemo/src/resourceapplicationcontext.xml ");
2. ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext( "/applicationcontext.xml ");
3. ServletContext servletContext = request.getSession().getServletContext();
   ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);

可以发现 spring的核心结构:

BeanFactory和BeanDefinition

无论是何种方式,使用AbstractApplicationContext#refresh())进行启动:

public void refresh() throws BeansException, IllegalStateException {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//加载配置并将注册bean
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);//为容器的某些子类指定特殊的BeanPost事件处理器
            this.invokeBeanFactoryPostProcessors(beanFactory); //调用所有注册的BeanFactoryPostProcessor的Bean 
            this.registerBeanPostProcessors(beanFactory);  //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 
            this.initMessageSource();//初始化信息源,和国际化相关
            this.initApplicationEventMulticaster();//初始化容器事件传播器.  
            this.onRefresh();//调用子类的某些特殊Bean初始化方法  
            this.registerListeners();//为事件传播器注册事件监听器.  
            this.finishBeanFactoryInitialization(beanFactory);//初始化所有剩余的单态Bean
            this.finishRefresh();//初始化容器的生命周期事件处理器,并发布容器的生命周期事件 
        } catch (BeansException var9) {
            if(this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();//销毁bean
            this.cancelRefresh(var9);//取消启动
            throw var9;
        } finally {
            this.resetCommonCaches();//重置缓存
        }

    }

1.加载配置,DefaultBeanDefinitionDocumentReader读取xml元素委托BeanDefinitionParserDelegate解析并注册bean信息(对应上文中ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory()),并由此构建了BeanFactory

(BeanFactory构建后,在bean未在加载前,我们可通过实现BeanFactoryPostProcessor进行扩展,见后续MyBeanFactoryPostProcessor)

public class BeanDefinitionParserDelegate{
......
/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}
......
}
public class BeanDefinitionReaderUtils {
......
/**
 * Register the given bean definition with the given bean factory.
 * @param definitionHolder the bean definition including name and aliases
 * @param registry the bean factory to register with
 * @throws BeanDefinitionStoreException if registration failed
 */
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String aliase : aliases) {
         registry.registerAlias(beanName, aliase);
      }
   }
}

......
}

MyBeanFactoryPostProcessor

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
        BeanDefinition bd = beanFactory.getBeanDefinition("tester");
        System.out.println("属性值============" + bd.getPropertyValues().toString());
    }
}

2.载入Bean并初始化(文中上部分finishBeanFactoryInitialization方法),检查Bean类的限定名是否存在,如果不存在,异常抛出;

at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
    at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:394)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1397)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1344)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:628)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:597)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1445)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:975)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:752)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:666)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:632)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:680)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:551)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:492)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)

对于bean的初始化进行扩展

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> aClass, String s) throws BeansException {
        System.out.println("postProcessBeforeInstantiation ...." + s);
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInstantiation ...." + s);
        return false;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues propertyValues, PropertyDescriptor[] propertyDescriptors, Object o, String s) throws BeansException {
        System.out.println("postProcessPropertyValues ...." + s);
        return propertyValues;
    }

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization ...." + s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization ...." + s);
        return o;
    }
}
/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization ...." + s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization ...." + s);
        return o;
    }
}

执行结果:

postProcessBeforeInstantiation ....tester
postProcessAfterInstantiation ....tester
postProcessBeforeInitialization ....tester
postProcessBeforeInitialization ....tester
postProcessAfterInitialization ....tester
postProcessAfterInitialization ....tester
postProcessBeforeInstantiation ....myInitializingBeanDisposableBean
postProcessAfterInstantiation ....myInitializingBeanDisposableBean
postProcessBeforeInitialization ....myInitializingBeanDisposableBean
postProcessBeforeInitialization ....myInitializingBeanDisposableBean

下面的实现是所有bean初始化后被执行

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyInitializingBean implements InitializingBean {
   
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("-----------afterPropertiesSet");
    }
}

3.获取bean(也就是在Service Locator):部分bean的初始化使用延迟初始化,也就是第一次向容器索要bean时实例化,通过工厂模式BeanFanctory去管理bean的生命周期(参考其实现类AbstractBeanFactory中createBean、doGetBean、getBean、destroyBean等方法)。

4.bean的销毁

public void destroy() {
    this.close();
}

public void close() {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.doClose();
        if(this.shutdownHook != null) {
            try {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
            } catch (IllegalStateException var4) {
                ;
            }
        }

    }
}

也可自定义

/**
 * Created by lucene on 2017/7/1.
 */
@Component
public class MyInitializingDisposableBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("-----------destroy");
    }
}

参考资料:

http://blog.csdn.net/hongxingxiaonan/article/details/49531891

http://uule.iteye.com/blog/2094609

© 著作权归作者所有

共有 人打赏支持
z
粉丝 1
博文 9
码字总数 12877
作品 0
朝阳
程序员
1 Spring核心:IoC容器的实现

依赖控制反转的实现有很多种方式。在Spring中,IoC容器是实现这个模式的载体, 它可以在对象生成或初始化时直接将数据注入到对象中,也可以通过将对象引用注入到对象数据域中的方式来注入对方...

qq_18150351
04/24
0
0
深入理解Spring源码(一)-IOC容器的定位,载入,注册

前言:Spring源码继承,嵌套层次非常多,读起来非常容易晕,小伙伴们在看文章的时候一定要跟着文章的思路自己去源码里点一点,看一看,并且多看几次。就会越来越清晰。下面开始正题 1.Spring...

Meet相识_bfa5
05/01
0
0
阿里老司机带你使用Spring框架快速搭建Web工程项目

摘要:Spring 框架是一个开源的 Java 平台,它为容易而快速的开发出耐用的 Java 应用程序提供了全面的基础设施。借助于Spring框架可以快速搭建Web工程项目,本文中阿里巴巴高级开发工程师嵛山...

萌萌怪兽
05/15
0
0
Spring基础篇——Spring容器和应用上下文理解

上文说到,有了Spring之后,通过依赖注入的方式,我们的业务代码不用自己管理关联对象的生命周期。业务代码只需要按照业务本身的流程,走啊走啊,走到哪里,需要另外的对象来协助了,就给Spr...

圆梦巨人
05/03
0
0
Spring IOC知识点一网打尽!

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工...

Java3y
05/22
0
0
Spring核心——注解自动装载

从配置上扩展 之前的文章介绍了Spring的IoC容器配置管理方面的详细内容,需要了解的可以从IoC容器的设计模式开始阅读。在介绍基于注解配置的配置之前我们再重复一下在之前提到的基本认识: ...

随风溜达的向日葵
前天
0
0
SpringBoot的幕后推手...

一、背景   这两年随着微服务的盛行,SpringBoot框架水到渠成的得到了高曝光,作为程序猿的我们,现在要是不知道一点SpringBoot相关的东西,貌似出去找工作都会被深深地鄙视,不过在我们开...

Java工程师-Distance
06/01
0
0
Spring MVC 原理探秘 - 容器的创建过程

1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的。Spring MVC 可对外提供服务时,说明其已经处于了就绪状态。再次之前,Spring MVC 需要进行一系列的初始化操作。...

coolblog.xyz
07/03
0
0
向Spring大佬低头——大量源码流出解析

用Spring框架做了几年的开发,只停留在会用的阶段上,然而Spring的设计思想和原理确实一个巨大的宝库。大部分人仅仅知道怎么去配,或着加上什么属性就能达到什么效果,这些东西都可以通过查文...

Java团长17
07/11
0
0
在spring中如何配置和使用一个Bean

在Spring中,那些组成你应用程序的主体(backbone)及由Spring IoC容器所管理的对象,被称之为bean。 简单地讲,bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中...

冰雷卡尔
2012/07/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

CoreText进阶(七)-添加自定义View和对其

CoreText进阶(七)-添加自定义View和对其 其它文章: CoreText 入门(一)-文本绘制 CoreText入门(二)-绘制图片 CoreText进阶(三)-事件处理 CoreText进阶(四)-文字行数限制和显示更多...

aron1992
11分钟前
0
0
Python爬虫 爬取百合网的女人们和男人们

学Python也有段时间了,目前学到了Python的类。个人感觉Python的类不应称之为类,而应称之为数据类型,只是数据类型而已!只是数据类型而已!只是数据类型而已!重要的事情说三篇。 据书上说...

p柯西
22分钟前
0
0
在Java中,你真的会日期转换吗

1.什么是SimpleDateFormat 在java doc对SimpleDateFormat的解释如下: SimpleDateFormatis a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows fo......

Java小铺
31分钟前
0
0
Linux系统梳理---系统搭建(二):tomcat的安装和使用

上一章讲到JDK的安装使用,这一章主要记录下服务器tomcat的安装以及部署一个项目. 1.下载tomcat,这里下载的是apache-tomcat-8.5.32.tar.gz 2.创建文件夹,便于管理,和JDK一样,在usr目录下创建t...

勤奋的蚂蚁
41分钟前
0
0
ES15-聚合

1.Terms Aggregation 分组聚合 2.Filter Aggregation 过滤聚合

贾峰uk
42分钟前
0
0
【2018.07.19学习笔记】【linux高级知识 20.27-20.30】

20.27 分发系统介绍 20.28 expect脚本远程登录 20.29 expect脚本远程执行命令 20.30 expect脚本传递参数

lgsxp
45分钟前
0
0
10.32/10.33 rsync通过服务同步~10.35 screen工具

通过服务的方式同步要编辑配置文件:[root@linux-xl ~]# vim /etc/rsyncd.confport=873log file=/var/log/rsync.logpid file=/var/run/rsyncd.pidaddress=192.168.43.21[tes...

洗香香
48分钟前
0
0
与女儿谈商业模式 (3):沃尔玛的成功模式

分类:与女儿谈商业模式 | 标签: 经济学 沃尔玛 陈志武 2007-05-10 09:09阅读(11279)评论(30) 与女儿谈商业模式 (3):沃尔玛的成功模式 陈志武 /文 沃尔玛(Wal-Mart)是另一个有意思的财...

祖冲之
55分钟前
0
0
网页加载速度优化方法总结

1、减少请求 最大的性能漏洞就是一个页面需要发起几十个网络请求来获取诸如样式表、脚本或者图片这样的资源,这个在相对低带宽和高延迟的移动设备连接上来说影响更严重。 2、整合资源 对开发...

Jack088
今天
0
0
dubbo学习

https://blog.csdn.net/houshaolin/article/details/76408399

喵五郎
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部