Spring原理深度解析(一)

Spring IoC实现(解耦)

BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承
IoC容器BeanFactory(基本)和ApplicationContext(高级),两个都是接口,需要具体实现类。(常用WebApplicationContext)
BeanDefinition是spring IoC容器存储的基本数据结构(xml配置文件等)。是对pojo的抽象。
BeanFactory接口(GenericBeanDefinition实现类)有getBean方法(最主要的方法,依赖注入的入口);isSingleton;isPrototype;isTypeMatch(是否是指定的class类型);getType(获取class类型);getAliases(获取别名)。
回调:A调用B,但B中有A的引用,B中再调用A,可以传入B中处理好的参数
IoC容器初始化
在配置文件中配置ContextLoaderListener监听器,并指定spring配置文件位置。
在这里插入图片描述
servlet容器启动(tomcat),为应用创建一个“全局上下文环境”:ServletContext ;容器调用web.xml中配置的contextLoaderListener,初始化WebApplicationContext上下文环境(即IoC容器,默认XmlWebApplicationContext),加载context-param指定的配置文件信息到IoC容器中。WebApplicationContext在ServletContext中以键值对的形式保存。此时开始IoC容器的初始化。
IoC容器的初始化由refresh()方法启动(这个方法在IoC具体实现类的构造函数中),启动包括BeanDefinition的Resouce定位(获取资源位置的Resource对象)、载入(解析xml配置文件,获取各个Element信息)和注册(将BeanDefinition放入HashMap中)三个基本过程。
Resource定位
构造IoC容器时,需要指定BeanDefinition的信息来源(如从xml文件中来),而这个信息来源需要封装成spring中的Resource类。Resource是Spring用来封装I/O操作的类。Resource是一个接口,具体实现类如ClassPathResource。通过配置文件指定的文件位置完成BeanDefinition的定位,但具体的数据还没开始读入。
Resource只是BeanDefinition位置的封装,具体操作由ResourceLoader完成。这个过程即找到BeanDefinition的位置,为其载入创造I/O操作的条件。
1、 构造函数调用refresh(),该方法在synchronized修饰的同步代码块中,保证不能有多个线程初始化。
2、 refresh()先调用createBeanFactory()创建容器
3、 refresh()再调用loadBeanDefinitions(BeanFactory)方法
4、 loadBeanDefinitions()先调用ResourceLoader得到Resource[]数组(定位)
5、 loadBeanDefinitions()再调用Reader读取器(如XMLBeanDefinitionReader)读取Resource[]中资源(完成I/O操作,即开始载入),利用回调把结果传入之前建立的BeanFactory中
很多不同的类都有loadBeanDefinitions方法,它们的功能也是不同的。
BeanDefinition的载入
把用户定义好的Bean表示成IoC容器内部的数据结构(即BeanDefinition)。BeanDefinition的载入分两部分,首先调用XML解析器得到document对象,但这些document对象没有按照spring的bean规则进行解析。接下来按照spring规则进行解析。
6、 在Reader读取器(如XMLBeanDefinitionReader的loadBeanDefinitions方法)中调用documentLoader(XML解析器)中的方法,获得document对象;
7、 在Reader读取器(如XMLBeanDefinitionReader的loadBeanDefinitions方法)再调用processBeanDefinition(传入document的element);
8、 processBeanDefinition (element,BeanDefinition)方法调用parseBeanDefinitionElement()方法,解析具体的元素标签(如、、等),将解析得到的结果设置到BeanDefinitionHolder中(BeanDefinitionHolder是BeanDefinition对象的封装类,封装了BeanDefinition、bean的名字等,用它来完成向IoC容器注册);
经过对document逐层解析,我们在XML中定义的BeanDefinition就被载入到了IoC容器中。但是,重要的依赖注入在这个时候还没有发生,现在IoC容器中BeanDefinition存在的还只是一些静态的配置信息。
BeanDefinition的注册
将BeanDefinition放入HashMap中,这些BeanDefinition数据在IoC容器中通过一个HashMap(ConcurrentHashMap<String,BeanDefinition>)来保持和维护,beanName为key,beanDefinition为value。
9、 在第8步processBeanDefinition()方法中调用registerBeanDefinition(BeanDefinitionHolder)开始注册,map.put(beanName,BeanDefinition),registerBeanDefinition中需要synchronized同步代码块,保证数据一致性。以上过程都是在Reader读取器类中完成的。
IoC容器的依赖注入
依赖注入的过程是用户第一次向IoC容器索要Bean时触发的(BeanFactory.getBean(name)),当然也有例外,也就是我们可以在BeanDefinition信息中通过控制lazy-init属性来让容器完成对Bean的预实例化(在初始化过程中完成,即在refresh()(初始化的入口)时调用getBean())。通过依赖注入生成实例。
1、 getBean()方法中,首先判断是否已经创建,且为单例,这种情况不要创建。然后根据Bean的名字获取BeanDefinition,当前取不到就到双亲BeanFactory中取,如果还取不到就顺着双亲链一直向上。
2、 取到BeanDefinition后,获取当前Bean所依赖的所有Bean,并递归调用getBean。
3、 通过createBean创建Bean的实例,最后返回Bean。
4、 createBean()中,调用createBeanInstance()创建Bean(默认使用CGLIB一个常用的字节码生成器类库、或使用JVM的反射);
5、 createBean()中,再调用populateBean()方法,将当前Bean的依赖注入,通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。
Bean的其他
Bean的预实例化:设置了lazy-init属性,在refresh方法中就会调用getBean
Bean对IoC容器的感知:实现ApplicationContextAware接口,可以在Bean中得到Bean所在的应用上下文(ApplicationContext),从而直接在Bean中使用(如getBean)。在IoC对Bean初始化时,会对Bean类型判断,如果是一个ApplicationContextAware的类型,那么IoC会调用其setApplicationContext方法,将ApplicationContext设置进去。
注解:扫描spring容器中指定包,找到包中加注解的类,然后将该类纳入spring容器
在这里插入图片描述
service,controller都是component

Spring依赖注入方式
• 1.Set注入
• 2.构造器注入
• 3.静态工厂的方法注入
• 4.实例工厂的方法注入
• Spring IOC注入方式用得最多的是(1)(2)种,多写多练就会非常熟练。
• 另外注意:通过Spring创建的对象默认是单例的,如果需要创建多实例对象可以在标签后面添加一个属性:

<bean name="..." class="..." scope="prototype">

通过IoC容器实现的依赖反转,把依赖关系的管理从Java对象中解放出来,交给了IoC容器来完成,从而完成了对象之间的关系解耦,利用cglib或反射实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值