本文档适用于使用过Spring的开发者,该文章有助于他们重新梳理一下对Spring的认识。
这篇文章是本人在项目开发中使用Spring的总结,这里只是归纳了我们在开发中经常要用到的Spring的特性,Spring的其他特性或者使用起来比较复杂,或者很少有机会在实际开发中使用将不再本文中做介绍。
一、背景,为什么我们需要Spring?
Martin Flower提出了IoC(Inversion of Control),反转的是什么样的控制?
以前我们在一个java对象中要使用另外一个java对象,即定义两个java bean之间的依赖关系,通常通过以下三种方式建立:
(1) Bean自己实例化另外一个bean。
(2) 在bean的构造函数中指定依赖关系。
(3) 使用类似service locator模式来获得另外一个bean。
这三种方式都是由bean自己自主控制依赖关系。
现在我们通过IoC容器来创建bean并注入它们之间的依赖关系。这样对象的创建和依赖关系的定义就由专门的IoC容器来实现,而不是由对象本身。这样就是我们所说的控制的翻转。好处:bean自己不再负责对象的依赖关系,从而降低对象之间的耦合。同时让开发者把精力放在业务逻辑的编写上。
这种控制翻转更确切的说是Dependency Injection(依赖注入),依赖关系通过容器来注入实现的。我们通过接口的方式实现它,这也符合DIP的原则,即Dependency Inversion Principle(依赖倒转原则:面对对象编程的基本原则)。
spring最新版本:
Spring Framework 2.0 (current production version 2.0.3)
我们公司大多数使用的
Spring Framework 1.2 (current production version 1.2.8)
Spring就是一个轻量级的IoC容器。IoC容器最主要的功能就是帮助我们管理对象,并建立他们的依赖关系。
二、Spring框架介绍
Core封装包是框架最基础的部分,提供IoC和依赖注入特性。
DAO提供了JDBC的抽象和封装,方便我们使用JDBC的方式访问数据库,同时提供了声明式事务管理的功能。
ORM提供了常用的ORM Mapping API(JPA, JDO, Hibernate, iBatis.)的集成。我们公司目前采用Spring提供的ibatis集成。
AOP提供了面向方面的编程实现,让我们可以方便的定义方法拦截器和切点。
WEB提供了针对web层开发的集成特性。
三、Core
org.springframework.beans 和org.springframework.context是spring IoC容器的基础。
org.springframework.beans.factory.BeanFactory初始化和配置Bean,装配它们之间的依赖关系。
ApplicationContext 是扩展了BeanFactory ,提供了更多的功能,在使用中Spring作者推荐是使用ApplicationContext。
几个重要的知识点:
(1) spring注入的方式:Setter注入和构造器注入。如果采用Setter方法注入,别忘了在类定义的时候加上setter方法,这一点开发者常常会忘掉,导致NullPointerException。
(2) 自动装配:Spring提供多种自动装配的功能,其中byName是最好用、最常用的。可以大大简化bean的定义。例子
<beans default-autowire="byName">
比如我们定义了一个bean 类,它包含了master属性,并且含有setMaster方法,那么spring会自动在IoC容器中寻找名为master的bean,然后调用setMaster将master对象赋值给master。
(3)Bean的作用域
Singleton
Spring容器只存在一个共享的bean实例,默认的配置。
<bean id="example" class="com.yz.bean.Example"/>
Prototype
每次对bean的请求都会创建一个新的bean实例。
<bean id="example" class="com.yz.bean.Example" singleton=”false”/>
两者如何选择?原则:所有有状态的bean都使用Prototype作用域,而对无状态的bean则应该使用singleton作用域。
(4) 熟悉Spring的配置文件xml中bean的定义,有助于我们灵活地定义bean。
Bean的定义的格式基本如下:
<bean id="example" class="com.yz.bean.Example"/>
id唯一标识该bean,要使用某个bean,只需在容器中通过id获得之,就可以获得它的一个实例。
Bean的属性定义如:<properyt name=””>
其属性值可以为:
l 其它bean:
ref bean=
ref local=
l 集合
<list> <set> <map> <props>
l 数字,字符串。
(6) bean定义中的继承关系,使用这种继承关系同样可以简化bean的定义,实际开发中经常被使用。
如果你希望你的java bean的实例能继承另外一个java bean的配置信息。那么你在定义该bean的时候要使用parent属性。
<bean id="childExample" class="com.yz.bean.ChildExample" parent="example"></bean>
尽管这两个bean实际上没有类的继承关系,也可以使用parent属性。这种parent属性的方式实际上提供了模板的形式。
(7) PropertyPlaceholderConfigure
用途:将spring中分布在不同的xml文件的一些属性值统一到一个文件来维护。这样可以提高我们程序的维护性,我们在实际开发中经常使用它。
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/com/yz/bean/common.properties"/>
</bean>
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
(8) 资源读取。
Spring来读取配置文件是按照以下的规则进行的:
前缀 |
例子 |
说明 |
classpath: |
classpath:com/myapp/config.xml |
从 classpath中载入。 |
file: |
file:/data/config.xml |
从文件系统载入。 |
http: |
http://myserver/logo.png |
作为URL载入。 |
(none) |
/data/config.xml |
取决于当前的ApplicationContext |
四、AOP
1、背景
AOP(Aspect-Oriented Programming)是对Object-Oriented Programming (OOP)的补充,
OOP通过类的继承实现功能的重用,如果某个功能是多个不同类型的类都需要具有的话,OOP就解决不了这个问题,这样就需要AOP来帮助我们
AOP通过切面来达到我们的实现可以跨越不同对象和类型。
Spring中的AOP主要用于:
(1) 提供声明式企业服务,比如声明的事务管理
(2) 允许使用者实现定制的aspects, 这是对OOP的补充。
2、概念
Joinpoint(连接点):程序执行过程中的某个特定的点。比如某个方法的调用或者异常。
通常我们希望在这个joinpoint上执行某个特殊的功能。Spring的AOP目前只支持连接点为方法的调用。
Aspect(切面):横切多个对象的关注点的模块化。比如事务处理,我们有多个对象都需要实现事务处理的功能,Aspect就是我们将多个对象共同关注的功能抽出独立出来。
Advice(通知):在某个特定的Joinpoint上切面执行的动作。通常我们通过拦截器interceptor或者advisor来实现,
Pointcut(切入点):符合某种规则的连接点。
目标对象:被代理的对象。
AOP代理:AOP框架创建的对象,用来代理我们的目标对象。
Spring缺省使用j2se动态代理来作为AOP的代理,如果要代理的类没有继承任何接口,spring使用CGLIB代理。Spring使用org.springframework.aop.framework.ProxyFactoryBean来产生代理对象。
3、简化代理定义
在实际开发中常常有许多相似的代理定义,那么我们可以创建一个模板bean,这个bean本身不会初始化,每个需要创建的代理都定义为这个bean的子bean。
五、spring的DAO
1、JDBC封装包
涉及spring的包:core, dataSource, object, and support。
org.springframework.jdbc.core由JdbcTemplate类以及相关的回调接口组成。
org.springframework.jdbc.datasource提供了简化DataSource访问的工具类。
org.springframework.jdbc.object提供了一些处理查询、更新、存储过程的类。
org.springframework.jdbc.support
提供了SQLException的转换类和相关的工具类。
Spring
将所有jdbc处理中抛出的异常转换为spring dao包中定义的异常,这些异常是unchecked exception,我们可以对这些异常有选择的捕获。这也是Spring提供的一个很重要的特性。
看例子:
2
、DataSource可以JNDI,或者apache提供的
dbcp,或者spring自带的DriverManagerDataSource。
3
、需要了解的知识:
(1) JdbcTemplate是线程安全的。
(2)
我们如果要获得connection,需要调用DataSourceUtils.getConncetion(),这个类会把SQLException的异常转换为spring的unchecked Exception,并且如果我们使用DataSourceTransactionManager的话,该connection会绑定到当前线程中。
JdbcTemplate
就是通过这种方式获得数据库连接的。
六、spring的ORM
Spring
的ORM提供了对常用ORM Mapping工具的封装,包括Hibernate、JDO、ibatis
等,ibatis由于使用和jdbc sql的访问方式相似,同时sql语句可控,便于DBA优化,所以深受普遍欢迎。
批量操作:
public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {
public void insertAccount(Account account) throws DataAccessException {
getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
executor.update("insertAccount", account);
executor.update("insertAddress", account.getAddress());
executor.executeBatch();
}
});
}
}
七、Spring的事务管理
1
、全局事务和本地事务
如果我们的应用涉及到多个事务性资源的参与(比如多个数据库),我们就需要使用全局事务,全局事务是由应用服务器管理的,我们它使用JTA。
本地事务是指只涉及单个事务资源(比如一台数据库)。应用服务器不涉及事务管理,不能跨越多个资源。
2
、spring的事务
Spring
使用
PlatformTransactionManager来管理事务。定义如下:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
3
、声明式事务管理
声明式事务管理,开发者不用编写事务代码就可以实现事务处理。
Spring
的事务管理是通过spring AOP来实现的。
我们通过TransactionProxyFactoryBean设置Spring事务代理,然后将目标对象包装在事务代理中。当定义TransactionProxyFactoryBean时,必须提供一个相关的PlatformTransactionManager的引用和事务属性。
<bean id="petStoreTarget">
</bean>
<bean id="petStore"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref bean="petStoreTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
4
、编程式事务管理
Object result = transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
查看本文来源