第一章 IoC容器
IoC定义:Inverse of Control 控制反转。将new接口实现类的权利交到第三方类(导演类)中。导演类负责实例化接口的实现类,然后注入到依赖类中。
类加载器和反射。通过反射的方式可以将配置文件中定义字符串变成类的实例(先通过全名限定,利用类加载器加载类进jvm),然后根据依赖关系注入到其他类中。
资源访问接口
——Resource接口的不同实现类负责从不同类型资源文件中加载资源。ResourceLoader资源加载器及其实现类PathMatchingResourcePatternResolver负责根据资源地址前缀和路径通配符加载资源。
——有了上述接口,spring容器将可以方便的加载配置文件中定义的bean信息,从而实现控制反转。
IoC容器:BeanFactory和ApplicationContext ApplicationContext基于BeanFactory两个容器在启动的时候必须初始化日志框架例如:log4j。不然spring启动将出错。
BeanFactory
——BeanFactory作为IoC容器的核心接口,通过不断的扩展性形成了一套继承体系。这套体系可以让开发者从不同层面使用容器。
——ConfigurableBeanFactory等接口可以为容器添加定制化的功能。例如:在bean生产的过程中添加一系列处理器,以增强bean的实例化过程。
——BeanFactory目前的实现类只有DefaultListableBeanFactory 而 XmlBeanFactory已经被废弃。
——XmlBeanDefinitonReader负责将配置文件的bean定义解析为BeanDefiniton类,为BeanFactory提供信息。ClassPathXmlApplicationContext中已经具备该能力。
——AnnotationConfigApplicationContext具备从java配置类中启动的能力。WebApplicationContext具备从web根路径启动的能力。WebApplicationContext中需引用ServletContext,同时自身也作为ServletContext属性,通过ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE键被引用
——Web环境中初始化WebApplicationContext有2中方式:自启动Servlet和ContextLoaderListen。低版本Servlet不支持监听的方式启动。启动只需在web中配置即可。
BeanFactory的生命周期
1. 生命周期过程: getBean()过程
——调用postProcessBeforeInstatiation()方法 1
——调用bean的构造器
——调用postProcessAfterInstantiation()方法 1
——调用postProcessProptertyValues()方法 1
——调用bean的属性器设置属性(注入配置文件中定义的属性依赖)
——调用setBeanName()方法 2
——调用setBeanFacotry()方法 2
——调用postProcessBeforeInitialization()方法 3
——调用afterPropertiesSet()方法 2
——调用init-method配置的初始化方法
——调用postProcessAfterInitialization()方法 3
——单例放入容器的缓冲池中。prototype交给调用者
——调用destroy()方法 2
——调用destroy-method配置的销毁方法
——整个生命周期中:1为容器级的处理器(InstantiationAwareBeanPostProcessor接口),负责处理所有bean的共性问题;2为bean级的处理器,定义在bean自身类中(通过实现BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean接口);3为容器级的处理器(BeanPostProcessor接口)。
——其中InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口。通过ConfigurableBeanFactory.addBeanPostProcess()方法可以将自定义的处理器加入到beanFactory中。
——容器在创建的过程中会检查这些接口,然后做相应处理。
——从上述生命周期过程可以看出,核心过程为调用bean的构造器,属性器,初始化方法,销毁方法的过程。各处理器为spring框架生命周期接口提供的额外控制。但使用spring不应对应用程序类做任何限制。所以一般不会注册这些处理器。AOP和注解例外。
ApplicationContextd的生命周期
——其生命周期与BeanFactory基本一致。
——在ApplicationContext启动的时候(<bean>被解析为BeanDefiniton时)可以注册BeanFactoryPostProcessor处理器,并调用postProcessBeanFactory()方法以对配置文件进行处理。该处理器可以直接在配置文件中声明实现了对应接口的bean来注册。
第二章:在IoC容器中装配Bean
Bean定义注册表:将配置中的bean定义加载进spring,通过id和BeanDefiniton描述。多个BeanDefinition形成了注册表
基于XML的配置
——spring2.0以后采用Schema格式的配置
——xmlns为默认的命名空间 一般为bean
——xmlsn:aop为aop指定命名空间,aop为命名空间的别名
——xmlns:xsi为xsi指定命名空间,然后可以通过xsi为所有命名空间指定xsi文件url
——xsi:schemaLocation通过xsi别名配置各命名空间的schema文件。
Bean的基本配置
——通过id和name为Bean命名,id全局唯一、不含特殊字符。name例外,但是同名将覆盖。
——依赖注入
——属性注入:配置<property name=><value></省略></>将通过反射寻找setXXX()方法注入。属性名前两个字母要么全大写要么全小写。
——构造器注入:<construction-arg index= type= ref=><value></></>多相似构造器下使用index和type唯一确定。ref引用其他bean
——工厂方法注入:<bean factory-bean="" factory-method=""/> 需先声明factory-bean这个Bean。
——静态工厂方法注入 <bean class="" factory-method="">
——<value>标签注入字面值 <![CDATA[...]]>让XML将里面字符当普通字符处理。没有值则为""字符串
——<bean/>将在属性中注入一个bean
——<ref parent="">引用父容器中的bean
——<null/>将注入Null
——<property name="class.property...">可以配置级联属性,不过必须在当前类里面有一个class的实例。
——<property name=""><list><value></></></>可以为list直接注入值。同理<set>也是一样,不过类中必须先有一个实例化的对象。
——<property name=""><list><entry><key><value></></><value></></></></>为map注入值。
——<prperty name=""><props><prop key="">sadf</><prop></></>方式为properties注入。只能注入字符串类型。
——通过util命名空间配置集合类型的bean
——<utils:list id="" list-class="java.util.LinkedList"><value></></util:list> map类型为<entry key="" value=""/><entry />
——使用p命名空间
——原来的使用property标签可以直接改为 p:name="小明" p:car-ref="car"设置属性和引用。
第三章:ApplicationContext
初始化步骤
1. 初始化BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
2. 调用工厂后处理器BeanFactoryPostProcessor 在BeanDefinition中找出实现此接口的Bean用来对BeanDefinition中未完成的Bean进行加工.
3. 注册bean后处理器 BeanPostProcess用于对bean实例化进行加工
4. 初始化消息源
5. 初始化应用上下文事件广播器
6. 初始化其他特殊的Bean onFresh()
7. 注册事件监听器
8. 初始化所有单实例的Bean,使用懒加载模式的Bean除外
9. 完成刷新并发布容器刷新事件。
BeanDefinition: 配置文件中<bean>标签解析后生成的对象,被注册到BeanDefinitionRegistry中。初步生成的BeanDefinition可能只是半成品,需要BeanFactoryPostProcessor对其进行加工。
来解析占位符为最终的实际值。
InstantialtionStrategy 通过不同策略实例化bean, 尚未设置属性
BeanWrapper 为Bean设置属性。主要通过属性编辑器来设置属性,通过BeanWrapper接口进行访问。
属性编辑器:
——PropertyEditorRegistrySupport为常见的类型提供了默认的属性编辑器。 注册属性编辑器:defaulEditors.put(char.class, new CharacterEditor(false));
——如果需要对复合类型进行转换需要自定义的属性编辑器。可以通过扩展PropertyEditorSupport类来实现自己的属性编辑器(覆盖 void setAsText(String text) 定义自定义解析器,然后调用父类setValue()设置转换后的属性),然后添加到注册map中。
CustomerEditorConfigurer类实现了工厂后处理器,将在spring初始化的时候,自动调用。所以只需在其customEditors属性中,加入自定义的编辑器类即可。
<bean class= "org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name = "customEditors">
<map>
<entry key = "com.xx.Xxx" value= "com.xxx.xxx.CustomXxxEditor">
</entry>
</map>
</property>
</bean>
这样就可以为某个类型注册一个属性编辑器,直接在配置文件中按照自定义格式设置字面值,属性编辑器会解析成对应复合类型。
——使用外部属性文件: PropertyPlaceholderConfigurer在对属性进行转换的时候,会去外部文件寻找值进行占位符替换。
该类实现了BeanFactoryPostProcessor接口在spring容器初始化的时候将自定调用(postProcessBeanFactory方法,在该方法中调用convertProperty方法设置属性值。)以完善BeanDefiniton对象的内容。
<bean class = "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location = "classpath:com/smart/placeholder/jdbc.properties">
p:fileEncoding = "utf-8" /> 可在该类中指定外部属性文件的地址和编码方式
或者:
<context:property-placeholder location="classpath:com.smart.jdbc.properties">
在其父类中PropertyResourceConfigurer类中,convertProperty(propertyName, propertyValue)用于在属性使用之前对属性值进行转换处理。可以用来对密码等属性进行加解密。
——应用其他bean的值:
#{beanName.beanproperty}可以直接引用其他bean中的属性值。