一、相关概念
1.容器:管理对象的生命周期(包括对象创建、对象的调用,对象的销毁)管理器,处理对象与对象之间的关系
2.容器提供的服务
*对象生命周期的管理
*对象依赖和配置管理
*对象池和线程池的管理
3.轻量级与重量级容器
轻量级体现在非侵入(类之间的关系上),不需要依赖容器提供的类
重量级有侵入的,
4.IoC(控制反转)
DI(dependency injection) 依赖注入
什么是依赖注入?注入的目的?
依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
5.依赖注入的三种方式
*接口注入 往往传递的是接口,而不是具体实现
* 设值注入 通过setter方法设值,没有具体的业务语义,很简洁
*构造注入 通过构造函数来创建对象,依赖关系体现在构造函数的参数上,
依赖关系集中
三、Spring初探
1.Spring环境的搭建
本环境采用的是Spring2.0的环境
1)jar包的引入
新建一个User Library 命名为spring(任意命名),引入必须要使用的jar文件,如下:
*%SPRING_HOME%/dist/spring.jar
*%SPRING_HOME%/lib/jakarta-commons/commons-logging.jar
*%SPRING_HOME%/lib/log4j/log4j-1.2.14.jar
2)拷贝spring配置文件和log4j的配置文件到项目src目录下
*%SPRING_HOME%/samples/jpestore/war/WEB-INF/applicationContext.xml
*%SPRING_HOME%/samples/jpestore/war/WEB-INF/log4j.properties
3)添加applicationContext.xml的标签智能提示
此处主要是导入XML文件的Schema文件,编辑相关XML文档是出现标签的提示
*window-->Preferecces--->MyEclipse Enterprise Workbench--->Files and Editors---->XML--->XMLCatalog---->右边Add XML Catalog--->打开了 Add XML Catalog Entry
Location 选择 %SPRING_HOME%\dist\resources\spring-beans-2.0.xsd
KeyType 选择Schema Location
Key 在自动生成的串后面加上/spring-beans-2.0.xsd
然后完成ok
2.Spring IoC快速入门
1)相关类和接口
实体类--->Permission
IPermissionService接口---PermissionServiceImpl实现,持有一个IPermssionDAO类型的引用permissionDAO方便调用DAO的方法
IPermissionDAO接口----->PermssionDAOImpl实现
本实例要使用两种方式的注入对PermssionServiceImpl类中permssionDAO的变量完成赋值.
2)通过get和set方法设值,注入方式
*首先要在PermissionServiceImpl建立permissionDAO的get和set方法
*要保证PermissionServiceImpl有一个无参的构造方法.,默认或者手动创建均可
*applicationContext的配置
创建一个bean的实例,便于下面注入引用
"<bean id="permissionDAO" class="yeah.developers.spring.PermissionDAOImpl"></bean>"
<bean id="permissionService" class="yeah.developers.spring.PermissionServiceImpl">
//通过get和set方法设值,注入方式
<property name="permissionDAO" ref="permissionDAO"></property>
</bean>
3)通过带参数的构造器实现,每个参数就是一个依赖,也可以通过静态的工厂方法实现
*首先要保证PermissionServiceImpl有带参的构造方法,用来初始化要通过注入方式赋值的成员变量
public PermissionServiceImpl(IPermissionDAO permissionDAO) {
this.permissionDAO = permissionDAO;
}
*applicationContext的配置
<bean id="permissionDAO" class="yeah.developers.spring.PermissionDAOImpl"></bean>
<bean id="permissionService" class="yeah.developers.spring.PermissionServiceImpl">
//构造注入方式,
<constructor-arg ref="permissionDAO"></constructor-arg>
</bean>
4)测试
//读取配置文件
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
//用用过Spring创建的Bean的实例,调用业务方法
IPermissionService permissionService = (IPermissionService) beanFactory.getBean("permissionService");
permissionService.addPermission(new Permission());
如果没有构造方法, 又没有get和set方法,譬如单例的情况Spring可以通过静态的工厂方法实现注入.
3.Bean处理和BeanWrapper
BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息、查询只读或者可写属性等功能
BeanWrapper封装了一个bean的行为,诸如设置和获取属性值等
代码示例:
Class c = Class.forName("yeah.developers.spring.Permission");
BeanWrapper bw = new BeanWrapperImpl(c.newInstance());
bw.setPropertyValue("name", "abc");
System.out.println(bw.getPropertyType("name"));
System.out.println(bw.getPropertyValue("name"));
4.JavaBean普通属性注入
TestBean包含属性,并生成了其对应的get和set方法
private int intValue;
private String stringValue;
private List listValue;
private Set setValue;
private String[] stringArray;
private Map mapValue;
配置文件
1)继承ProperyEditorSupport,例如实现一个日期类型的转换器
3)完成之后调用父类的super.setValue(date);
4)注册到Spring IOC容器
由于CustomDateEditor 是构造注入,有构造方法
通过Spring给创建的bean的实例默认为scope="singleton",即一个单例,我们可以通过<bean>标签上的scope属性,灵活控制对象的作用域.
在没有Servlet容器的时候,Bean只有如下两种作用域
singleton(默认) 在每个Spring IoC容器中一个bean定义对应一个对象实例
prototype 一个bean定义对应多个对象实例
多线程的情况下应该使用prototype,避免多个线程同时对同一个bean对象执行set操作.
8.自动装配(AutoWire)
Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系.autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以给我们的配置文件减减肥.
在xml配置文件中,autowire一共有五种类型,可以在<bean/>元素中使用autowire属性指定:
*no 不使用自动装配。必须通过ref元素指定依赖(ref指定到对应的bean id),这是默认设置。由于显式指定协作者可以使配置更灵活、更清晰,因此对于较大的部署配置,推荐采用该设置.如下:
创建3个类Bean1,Bean2,Bean3,类Bean1有一个Bean2类型的成员变量bean2,类Bean2 有一个Bean3类型的成员变量bean3,下面两种自动装配的测试均采用这几个测试类,
如果配置文件的<beans>标签中设置Default-autowire="byName":配置文件就可以写成下面这个样子,由Spring IoC容器自动装配
<bean id="bean1" class="yeah.developers.spring.Bean1"></bean>
<bean id="bean2" class="yeah.developers.spring.Bean2"></bean>
<bean id="bean3" class="yeah.developers.spring.Bean3"></bean>
必须保证Bean类里面的成员变量必须在配置文件里有id与自己变量名相同的对应类型的Bean.
* byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配
如果配置文件的<beans>标签中设置Default-autowire="byType":配置文件就可以写成下面这个样子,由SpringIoC容器自动装配
<bean ></bean>
<bean id="bean22" class="yeah.developers.spring.Bean2"> </bean>
<bean id="bean33" class="yeah.developers.spring.Bean3"></bean>
测试代码:
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean1 Bean1 = (Bean1) beanFactory.getBean("bean1");
Bean2 Bean2 = (Bean2) beanFactory.getBean("bean22");
这样也能完成自动装配,因为Ioc容器中只存在一个与相应的Bean1,Bean2中属性相同的Bean;
这种方式下,类里面的实例变量的名字不一定要和applicationContext.xml 中 定义的bean 的ID对应,只要类型能够匹配就可以装配上
9.Bean定义的继承
如下两个类成年人和未成年人类:
父Bean需要在其对应的<bean>标签定义abstract="true"的属性
10.国际化
ApplicationContext接口扩展了MessageSource接口,因而提供了消息处理的功能(i18n或者国际化)。当ApplicationContext被加载时,它会自动在context中查找已定义为MessageSource类型的bean。此bean的名称须为messageSource。
MessageSource 提供的常用方法:
String getMessage(String code, Object[] args, String default, Locale loc):用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的MessageFormat来作消息中替换值。
读取国际化资源文件示例如下
Spring Ioc容器自动创建的messageSource的实例,通过AuthCheck类中MessageSource类型变量的set方法,注入,为属性赋值
1.容器:管理对象的生命周期(包括对象创建、对象的调用,对象的销毁)管理器,处理对象与对象之间的关系
2.容器提供的服务
*对象生命周期的管理
*对象依赖和配置管理
*对象池和线程池的管理
3.轻量级与重量级容器
轻量级体现在非侵入(类之间的关系上),不需要依赖容器提供的类
重量级有侵入的,
4.IoC(控制反转)
DI(dependency injection) 依赖注入
什么是依赖注入?注入的目的?
依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
5.依赖注入的三种方式
*接口注入 往往传递的是接口,而不是具体实现
* 设值注入 通过setter方法设值,没有具体的业务语义,很简洁
*构造注入 通过构造函数来创建对象,依赖关系体现在构造函数的参数上,
依赖关系集中
三、Spring初探
1.Spring环境的搭建
本环境采用的是Spring2.0的环境
1)jar包的引入
新建一个User Library 命名为spring(任意命名),引入必须要使用的jar文件,如下:
*%SPRING_HOME%/dist/spring.jar
*%SPRING_HOME%/lib/jakarta-commons/commons-logging.jar
*%SPRING_HOME%/lib/log4j/log4j-1.2.14.jar
2)拷贝spring配置文件和log4j的配置文件到项目src目录下
*%SPRING_HOME%/samples/jpestore/war/WEB-INF/applicationContext.xml
*%SPRING_HOME%/samples/jpestore/war/WEB-INF/log4j.properties
3)添加applicationContext.xml的标签智能提示
此处主要是导入XML文件的Schema文件,编辑相关XML文档是出现标签的提示
*window-->Preferecces--->MyEclipse Enterprise Workbench--->Files and Editors---->XML--->XMLCatalog---->右边Add XML Catalog--->打开了 Add XML Catalog Entry
Location 选择 %SPRING_HOME%\dist\resources\spring-beans-2.0.xsd
KeyType 选择Schema Location
Key 在自动生成的串后面加上/spring-beans-2.0.xsd
然后完成ok
2.Spring IoC快速入门
1)相关类和接口
实体类--->Permission
IPermissionService接口---PermissionServiceImpl实现,持有一个IPermssionDAO类型的引用permissionDAO方便调用DAO的方法
IPermissionDAO接口----->PermssionDAOImpl实现
本实例要使用两种方式的注入对PermssionServiceImpl类中permssionDAO的变量完成赋值.
2)通过get和set方法设值,注入方式
*首先要在PermissionServiceImpl建立permissionDAO的get和set方法
*要保证PermissionServiceImpl有一个无参的构造方法.,默认或者手动创建均可
*applicationContext的配置
创建一个bean的实例,便于下面注入引用
"<bean id="permissionDAO" class="yeah.developers.spring.PermissionDAOImpl"></bean>"
<bean id="permissionService" class="yeah.developers.spring.PermissionServiceImpl">
//通过get和set方法设值,注入方式
<property name="permissionDAO" ref="permissionDAO"></property>
</bean>
3)通过带参数的构造器实现,每个参数就是一个依赖,也可以通过静态的工厂方法实现
*首先要保证PermissionServiceImpl有带参的构造方法,用来初始化要通过注入方式赋值的成员变量
public PermissionServiceImpl(IPermissionDAO permissionDAO) {
this.permissionDAO = permissionDAO;
}
*applicationContext的配置
<bean id="permissionDAO" class="yeah.developers.spring.PermissionDAOImpl"></bean>
<bean id="permissionService" class="yeah.developers.spring.PermissionServiceImpl">
//构造注入方式,
<constructor-arg ref="permissionDAO"></constructor-arg>
</bean>
4)测试
//读取配置文件
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
//用用过Spring创建的Bean的实例,调用业务方法
IPermissionService permissionService = (IPermissionService) beanFactory.getBean("permissionService");
permissionService.addPermission(new Permission());
如果没有构造方法, 又没有get和set方法,譬如单例的情况Spring可以通过静态的工厂方法实现注入.
3.Bean处理和BeanWrapper
BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息、查询只读或者可写属性等功能
BeanWrapper封装了一个bean的行为,诸如设置和获取属性值等
代码示例:
Class c = Class.forName("yeah.developers.spring.Permission");
BeanWrapper bw = new BeanWrapperImpl(c.newInstance());
bw.setPropertyValue("name", "abc");
System.out.println(bw.getPropertyType("name"));
System.out.println(bw.getPropertyValue("name"));
4.JavaBean普通属性注入
TestBean包含属性,并生成了其对应的get和set方法
private int intValue;
private String stringValue;
private List listValue;
private Set setValue;
private String[] stringArray;
private Map mapValue;
配置文件
<bean id="testBean" class="yeah.developers.spring.TestBean">
<property name="intValue">
<value>1</value>
</property>
<property name="stringValue">
<value>string</value>
</property>
<property name="listValue">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="setValue">
<set>
<value>365</value>
<value>jerry</value>
<value>developers@yeah.net</value>
</set>
</property>
<property name="stringArray">
<list>
<value>000</value>
<value>111</value>
<value>222</value>
</list>
</property>
<property name="mapValue">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
</map>
</property>
</bean>
测试
BeanFactory beanFactory = new ClassPathXmlApplicationContext(
"applicationContext.xml");
TestBean testBean = (TestBean) beanFactory.getBean("testBean");
System.out.println(testBean.getIntValue());
System.out.println(testBean.getStringValue());
System.out.println(testBean.getListValue());
System.out.println(testBean.getSetValue());
System.out.println(testBean.getStringValue());
System.out.println(testBean.getMapValue());
5.注册用户自定义的PropertyEditor
1)继承ProperyEditorSupport,例如实现一个日期类型的转换器
public class DateConverter extends PropertyEditorSupport {
String pattern;
重写public void setAsText(String text)
public void setAsText(String text){
SimpleDateFormat sd = new SimpleDateFormat(pattern);
Date date = sd.parse(text);
完成之后调用父类的super.setValue(date)
super.setValue(date);
}
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
2)重写public void setAsText(String text)
3)完成之后调用父类的super.setValue(date);
4)注册到Spring IOC容器
*注册自定义的转换器
<bean id="dateConverter" class="yeah.developers.spring.DateConverter">
<property name="pattern" value="yyyy-MM-dd"></property>
</bean>
*注册到IoC容器
<bean id="dateConverter_register" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value-ref="dateConverter"></entry>
</map>
</property>
</bean>
6.配置Spring已经定义好但是没有注册的转换器(CustomDateEditor)
由于CustomDateEditor 是构造注入,有构造方法
CustomDateEditor(DateFormat dateFormat, boolean allowEmpty),需要DateFormate的实例
构造simpleDateFormate通过构造注入方式赋值给CustomDateEditor的成员变量
<bean name="simpleDateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd"></constructor-arg>
</bean>
*创建CustomDateEditor的Bean的实例
<bean id="dateConverter"
class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg ref="simpleDateFormat"></constructor-arg>
<constructor-arg value="true"></constructor-arg>
</bean>
*将创建好的CustomDateEditor实例注册到SrpingIOC容器中
<bean id="dateConverter_register"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value-ref="dateConverter"></entry>
</map>
</property>
</bean>
7.bean的作用域
通过Spring给创建的bean的实例默认为scope="singleton",即一个单例,我们可以通过<bean>标签上的scope属性,灵活控制对象的作用域.
在没有Servlet容器的时候,Bean只有如下两种作用域
singleton(默认) 在每个Spring IoC容器中一个bean定义对应一个对象实例
prototype 一个bean定义对应多个对象实例
多线程的情况下应该使用prototype,避免多个线程同时对同一个bean对象执行set操作.
8.自动装配(AutoWire)
Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系.autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以给我们的配置文件减减肥.
在xml配置文件中,autowire一共有五种类型,可以在<bean/>元素中使用autowire属性指定:
*no 不使用自动装配。必须通过ref元素指定依赖(ref指定到对应的bean id),这是默认设置。由于显式指定协作者可以使配置更灵活、更清晰,因此对于较大的部署配置,推荐采用该设置.如下:
创建3个类Bean1,Bean2,Bean3,类Bean1有一个Bean2类型的成员变量bean2,类Bean2 有一个Bean3类型的成员变量bean3,下面两种自动装配的测试均采用这几个测试类,
<bean >
<property name="bean2" ref="bean2"></property>
</bean>
<bean id="bean2" class="yeah.developers.spring.Bean2">
<property name="bean3" ref="bean3"></property>
</bean>
<bean id="bean3" class="yeah.developers.spring.Bean3">
</bean>
* byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配,也就是,类里面的实例变量的名字一定要和applicationContext.xml中的定义bean 的id对应,才能自动装配上.
如果配置文件的<beans>标签中设置Default-autowire="byName":配置文件就可以写成下面这个样子,由Spring IoC容器自动装配
<bean id="bean1" class="yeah.developers.spring.Bean1"></bean>
<bean id="bean2" class="yeah.developers.spring.Bean2"></bean>
<bean id="bean3" class="yeah.developers.spring.Bean3"></bean>
必须保证Bean类里面的成员变量必须在配置文件里有id与自己变量名相同的对应类型的Bean.
* byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配
如果配置文件的<beans>标签中设置Default-autowire="byType":配置文件就可以写成下面这个样子,由SpringIoC容器自动装配
<bean ></bean>
<bean id="bean22" class="yeah.developers.spring.Bean2"> </bean>
<bean id="bean33" class="yeah.developers.spring.Bean3"></bean>
测试代码:
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean1 Bean1 = (Bean1) beanFactory.getBean("bean1");
Bean2 Bean2 = (Bean2) beanFactory.getBean("bean22");
这样也能完成自动装配,因为Ioc容器中只存在一个与相应的Bean1,Bean2中属性相同的Bean;
这种方式下,类里面的实例变量的名字不一定要和applicationContext.xml 中 定义的bean 的ID对应,只要类型能够匹配就可以装配上
9.Bean定义的继承
如下两个类成年人和未成年人类:
public class Adolecense {
private int id;
private String name;
private String studentCardId;
//get和set方法省略
}
public class Adult {
private int id;
private String name;
private String cardId;
}
可以看出两个类有共同的属性id,name,Spring Ioc容器依赖注入支持Bean定义继承,如下:
父Bean需要在其对应的<bean>标签定义abstract="true"的属性
<bean id="commonBean" abstract="true">
<property name="id">
<value>100</value>
</property>
<property name="name">
<value>felix</value>
</property>
</bean>
子Bean需要在其对应的<bean>标签中定义parent=父Bean的ID属性
<bean id="adult" class="yeah.developers.spring.Adult"
parent="commonBean">
<property name="cardId">
<value>bj001</value>
</property>
</bean>
<bean id="adolecense" class="yeah.developers.spring.Adolecense"
parent="commonBean">
<property name="studentCardId">
<value>bj_stu_001</value>
</property>
</bean>
注意:抽象bean定义可作为子bean定义的模板,不能被Spring Ioc容器实例化,子bean会继承父Bean的所有属性,如果子bean中重新设置了与父Bean中相同的属性,那么会覆盖父Bean的属性..
10.国际化
ApplicationContext接口扩展了MessageSource接口,因而提供了消息处理的功能(i18n或者国际化)。当ApplicationContext被加载时,它会自动在context中查找已定义为MessageSource类型的bean。此bean的名称须为messageSource。
MessageSource 提供的常用方法:
String getMessage(String code, Object[] args, String default, Locale loc):用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的MessageFormat来作消息中替换值。
读取国际化资源文件示例如下
BeanFactory beanFactory = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MessageSource messageSource = (MessageSource) beanFactory.getBean("messageSource");
String message= messageSource.getMessage("user.name", null, "Resource can not find !", null);
配置示例如下:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>yeah.developers.spring.MessageResources</value>
</list>
</property>
</bean>
//此处配置authCheck为了不用每次都通过读取配置文件每次都拿到BeanFactory,然后再拿到MessageSource对象.
<bean id="authCheck" class="yeah.developers.spring.AuthCheck">
<property name="messagesource" ref="messageSource"></property>
</bean>
AuthCheck类代码:
public class AuthCheck {
MessageSource messagesource;
public void setMessagesource(MessageSource messagesource) {
this.messagesource = messagesource;
}
public void check(){
String message = messagesource.getMessage("user.name", new Object[]{"jerry"}, "Resource can not find !", null);
System.out.println(message);
}
}
Spring Ioc容器自动创建的messageSource的实例,通过AuthCheck类中MessageSource类型变量的set方法,注入,为属性赋值