Spring下载
Spring源码:https://github.com/WestieLee/spring-framework/releases
Spring文档:http://repo.spring.io/release/org/springframework/spring/
什么是IOC?
IOC亦称为“依赖倒置原理”,哪些方面的控制被反转了呢?依赖对象的获得被反转了。通过使用IOC容器,对象依赖关系的管理被反转了,转到IOC容器中来了,对象之间的相互依赖关系由IOC容器进行管理,并由IOC容器完成对象的注入。简而言之就是IOC容器来管理对象之间的依赖关系并完成对象的注入。
那具体什么是IOC容器呢?BeanFactory和ApplicationContext都可以看成是容器的具体表现形式。结合下文中的容器系列图举例说明:
BeanFactory就如上图顶层的瓶子它定义了IOC容器的最基本的功能规范,它也是一个容器;上图最底层的是一个个具体形状的瓶子就相当于FileSystemXmlApplicationContext、ClassPathXmlApplication等具体的容器,Spring为了去适配不同的场景而生产了这些容器。
SpringIOC容器系列
为了方便不同场景的使用,SpringIOC容器系列适配了多种应用场景,SpringIOC容器系列有两个主要容器系列:
① BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能
② ApplicationContext(应用上下文),ApplicationContext继承了BeanFactory,它是容器的高级形态,应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。
“SpringIOC容器适配多种应用场景“是什么意思呢?比如在某个容器系列中可以看到读取不同配置信息的各种容器,从不同I/O源读取配置信息的各种容器设计,更加面向框架的容器应用上下文的容器设计等。这些就是SpringIOC容器适配不同的应用场景的设计。
![](http://static.oschina.net/uploads/img/201506/29134759_lKLB.jpg)
BeanDefinition
对IOC容器来说, BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构,简单的说就是xml中定义的bean等信息最后会被解析成BeanDefinition对象,依赖反转功能都是围绕这个BeanDefinitiond的处理来完成的。
IOC容器初始化过程
ContextLoaderListener监听器负责完成IOC容器在Web容器中的初始化,IOC具体的载入过程是由ContextLoaderListener交由ContextLoader来完成的,ContextLoader是ContextLoaderListener的基类。
IOC容器的启动是由AbstractApplicationContext.refresh()方法启动的,这个启动过程包括BeanDefinition的Resource定位、载入、和注册三个基本过程。① Resource定位指的是BeanDefinition的资源定位它由ResourceLoader通过统一的Resource接口来完成。
② BeanDefinition的载入,即把用户定义好的Bean解析成容器内部的数据结构BeanDefinition。
③ 向IOC容器注册BeanDefinition。IOC容器内部是将BeanDefinition注入到一个HashMap中。
④ 注意:这里谈的是IOC容器初始化过程,在这个过程中, 一般不包含Bean依赖注入的实现,在SpringIOC的设计中,Bean定义的载入和依赖注入是两个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候(设置lazyinit除外,设置了该属性会在IOC初始化时就注入了)
2、注入方式:SET注入、构造器注入、接口注入
3、在Spring IOC容器的设计中,有两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。
4、IOC容器由很多,但IOC核心就其中一个。我们通常所说的IOC容器,实际上代表着一系列功能各异的容器产品,只是容器的功能有大有小,有各自的特点。作为IOC容器,也需要为它的具体实现指定基本的功能规范,这个功能规范的设计表现为接口类BeanFactory
5、用户使用容器时,可以使用转义符“&”来得到FactoryBean本身,用来区分通过容器来获取FactoryBean产生的对象和获取FactoryBean本身。举例来说,如果myJndiObject是一个FactoryBean,那么使用&FactoryBean得到的是FactoryBean,而不是myJndiObject这个FactoryBean产生出来的对象。
一、读取配置文件applicationContext.xml (获得Spring容器对象的两种方式)
// 方法一:ApplicationContext
ApplicationContext applicationContext
= new ClassPathXmlApplicationContext("cn/test/spring/b_springhelloworld/applicationContext.xml");
// ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext_dao.xml", this.getClass());
// 从中取出配置的Bean
User user = (User) applicationContext.getBean("user");
// 方法二:Resource
//获取配置文件
Resource resource = new ClassPathResource("cn/test/spring/b_springhelloworld/applicationContext.xml");
//工厂需要从配置文件中获取相应的信息
BeanFactory beanFactory = new XmlBeanFactory(resource);
// 从中取出配置的Bean
User user = (User) beanFactory.getBean("user");
ApplcationContext是BeanFactory的子接口,BeanFactory通常称为Bean容器,ApplicationContext通常称为应用上下文。ApplicationContext的功能要多于BeanFactory,如它可以加载外部的资源文件、可以自动进行AOP切面、可以识别自动代理的类、可以识别用于监听Bean创建的类等。
ApplicationContext的常用方法:
// 一次加载多个配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {"aaa.xml","bbb.xml"});
//获取配置文件中定义的bean的数量
ac.getBeanDefinitionCount();
//获取配置文件中定义的bean的所有名字,返回的是一个String数组
ac.getBeanDefinitionNames();
// 获取属于指定类型的bean的名称
String[] names = ac.getBeanNamesForType(User.class);
// 获取属于指定类型的bean的信息(key是名称,value是对象实例)
Map<String, Object> map = ac.getBeansOfType(UserDao.class);
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton" lazy-init="default" init-method="init" destroy-method="destroy">
scope属性:用于指定bean的生命周期
singleton:单例的,每次ac.getBean()返回的都是同一个实例.
prototype:多例的,第次ac.getBean()返回的都是一个新的实例. 默认为singleton。
init-method:初始化方法,单例和多例都会调用该方法,但必须关闭ApplicationContext,由于ApplicationContext没有close方法,要想调用必须转换成子类
destroy-method:多例时不会调用,单例可以调用
lazy-init属性:用于指定在什么时候初始化单例的对象
false:表示在创建ApplicationContext时就初始化本单例的对象。
true:表示在第一次调用getBean()获取本对象时才初始化。 默认为default.
如果想要所有的bean都是懒初始化,可以在<beans default-lazy-init=”true”>在<bean lazy-inti=”default”>
Bean的继承
<span style="font-family:Microsoft YaHei;"> <!--
配置dao,如果这个bean只是用于抽取出的多个bean的公共配置,则加上abstract="true", 这时就不需要写class属性。
-->
<bean id="baseDao" abstract="true">
<property name="dataSource" value="myDataSource"></property>
</bean>
<!-- 在其他bean中,可以指定parent属性,表示要从哪个父bean继承过来一些公共的配置 -->
<bean id="myUserDao" parent="baseDao" class="cn.itcast.spring.h_beanproperty.UserDao"></bean>
<bean id="myRoleDao" parent="baseDao" class="cn.itcast.spring.h_beanproperty.RoleDao"></bean></span>
二、Resource
1)ClassPathResource是从classpath中读取
2)FileSystemResource 从文件系统中读取
3)UrlResource 从指定URL中读取
4)ServletContextResource 必须要在web环境下使用
使用特定格式的字符串表示各种类型的Resource,格式如下:
三、依赖注入
(1)Set注入
<span style="font-family:Microsoft YaHei;"><bean name="user3" class="cn.test.spring.h_beanproperty.User">
<!-- 1、通常设置 -->
<property name="name" value="张三"></property>
<!-- 2、给name设置空值 -->
<property name="name" >
<null />
</property>
<!-- 3、 Set集合(String型)
Set集合(Integer型) 如果指定强类型,如Set<Integer>,则配置时可以不指定type,Spring能自动转换。
如果没有指定类型,默认当成String处理。这时指定明确的指定了类型,Spring才可以进行转换
-->
<property name="addressSet">
<set>
<value>棠东东路</value>
<value>御富科贸园</value>
</set>
</property>
<property name="numberSet">
<set>
<value type="java.lang.Integer">10</value>
<value type="java.lang.Integer">20</value>
</set>
</property>
<!-- 4、List集合 -->
<property name="addressList">
<list>
<value>棠东东路</value>
<value>御富科贸园</value>
<value>御富科贸园</value>
</list>
</property>
<!-- 5、数组,与List集合的配置一样 -->
<property name="addressArray">
<list>
<value>棠东东路</value>
<value>御富科贸园</value>
<value>御富科贸园</value>
</list>
</property>
<!-- 6、Map集合 -->
<property name="addressMap">
<map>
<entry key="地址1" value="棠东东路"></entry>
<entry key="地址2" value="御富科贸园"></entry>
</map>
</property>
<!-- 7、Properties集合 -->
<property name="properties">
<props>
<prop key="pageSize">20</prop>
<prop key="maxFileSize">1000K</prop>
</props>
</property>
</bean></span>
(2)构造放注入
<span style="font-family:Microsoft YaHei;"><!-- 通过构造方法注入 -->
<bean name="user2" class="cn.itcast.spring.h_beanproperty.User">
<constructor-arg value="2"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
</bean></span>
(3)注解注入。注解不能提供所有的注入,主要是定义Bean与Bean之间的依赖关系
// 使用@Component注解可以定义一个bean,bean的名称可以不写,默认为类的简单名称且第1个字母小写。
以下几个注解的作用一样,只是名称不一样,是为了区分bean的作用。
@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Controller用于标注控制层组件(如struts中的action
@Service用于标注业务层组件
@Repository用于标注数据访问组件,即DAO组件。
@Resource是用于注入依赖的bean:
可以通过name属性指定所需要的bean的名称,如果找不着,则抛异常。
或可以通过type属性指定所需要的bean的类型,
如果只有一个bean匹配这个类型,则就是他.
如果有多个bean匹配这个类型,则使用名称与字段或属性相同的,如果名称都不与当前属性或字段名相同,则抛异常。
或可以什么都不指定,默认是先按当前字段或属性的名称查找,如果找不到,再按类型查找,就抛异常。
@Scope注解用于指定bean的生命周期。@Scope("prototype")多例
(4)配置自动扫描,如果有多个包可以用逗号隔开
<span style="font-family:Microsoft YaHei;"> <context:component-scan base-package="com.cyqg.os"></context:component-scan></span>
四、控制反转
IOC控制反转:就是应用程序不再创建和维护对象了,它只负责使用对象【可以通过注入等方式传递进来】,所有的创建与维护都转移到了外部容器,控制权都交给外部容器。
五、读取外部的配置文件
<span style="font-family:Microsoft YaHei;"><!-- 加载外部的properties配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置数据库连接池(c3p0) -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 基本信息 -->
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="user" value="${username}"></property>
<property name="password" value="${password}"></property></span>
六、Spring远程调用(RMI)
实体需implements Serializable
ioc,是将对象,放至缓存
spring aop做的并不全