完美的东西往往有一个致命的缺点,那就是不真实。——《周浩晖精选集》
Spring是分层的JavaSE/EE full-stack(一站式) 轻量级开源框架
服务器端三层结构 (web层、业务层、持久层)
Servlet + JSP —- web层技术 —- Struts2框架或SpringMVC框架
JDBC 接口 —- 持久化技术 —- Hibernate框架或Mybatis框架
EJB 框架(复杂) —- 业务层技术 —- Spring 框架 (取代EJB出现 )
(1)方便解耦,简化开发(Spring IoC特性)
(2)AOP编程的支持
(3)声明式事务的支持
(4)方便程序的测试
(5)方便集成各种优秀框架 (整合Struts2 、 Hibernate 、MyBatis 、Struts1 )
(6)降低JavaEE API的使用难度 (Spring 提供大量工具类, 简化代码编写 )
图中将spring分为5个部分:core、aop、data access、web、test,图中每个圆角矩形都对应一个jar,如果在maven中配置,所有这些jar的“groupId”都是“org.springframework”,每个jar有一个不同的“artifactId”,另外,“instrumentation”有两个jar,还有一个“spring-context-support”图中没有列出,所以spring4的jar包一共是20个.
核心容器包含spring-core、spring-beans、spring-context、spring-context-support和spring-expression (Spring Expression Language,Spring表达式语言)这些模块。
核心容器包含spring-core、spring-beans、spring-context、spring-context-support和spring-expression (Spring Expression Language,Spring表达式语言)这些模块。
Web层包含spring-web、spring-webmvc、spring-websocket和spring-webmvc-portlet模块。
(1)IoC: 控制反转, 解决程序对象紧密耦合问题(工厂+反射+ 配置文件), 将程序中原来构造对象的权限,交给IoC容器来构造,当程序需要对象,找IoC容器获取;
(2)DI : 依赖注入 , IoC容器需要为程序提供依赖对象,返回对象所依赖对象一同可以提供(Servlet需要Service, 找Ioc容器获取Service, Service由容器提供,Service依赖DAO ,IoC容器提供Service对象同时, 将Service依赖DAO 注入到Service中)
ApplicationContext 是 BeanFactory 子接口,BeanFactory 才是Spring框架最核心工厂接口。
ApplicationContext 是对BeanFactory 接口扩展, 企业开发很少直接使用BeanFactory
ApplicationContext 会在容器初始化时,对其中管理Bean对象进行创建, BeanFactory 会在对象获取时才进行初始化 。
BeanFactory 在解析配置文件时并不会初始化对象,只有在使用对象时(getBean())才会对该对象进行初始化
ApplicationContext 在解析配置文件时对配置文件中的所有对象都初始化了,getBean()方法只是获取对象的过程
三种实例化Bean的方式
方式一: 使用类构造器实例化对象
<bean id="bean1"
class="cn.itcast.spring.b_instance.Bean1" />
方式二: 使用静态工厂 静态方法,对对象实例化
<bean id="bean2"
class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2" />
方式三: 使用实例工厂 实例方法 对对象实例化
<bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory" />
<bean id="bean3" factory-bean="bean3Factory"
factory-method="getBean3" />
应用场景: 大多数情况,可以通过构造器直接实例化, 只有在对象构造过程非常复杂的情况下,才会采用工厂实例化的方式
Spring为Bean对象,提供五种作用域
最常用 singleton 和 prototype 两种
Singleton (单例): 在一个BeanFactory对象中,引用唯一的一个目标实例
Prototype (多例): 每次通过工厂执行getBean时,返回不同实例对象
Request (请求范围) : 创建对象保存在request范围,如果request销毁,对象销毁
Session (会话范围): 创建对象保存Session中, 如果session销毁,对象销毁
* globalSession (全局会话 ) :分布式系统,全局会话的概念, 一次登录,应用多个系统
单例Bean 在容器初始化时,实例化 (只实例化一次 )
多例Bean 在工程执行getBean时 才会实例化 (每调用一次,返回不同对象 )
可以通过 init-method属性配置 Bean对象初始化执行方法,destory-method属性配置Bean对象销毁的方法
(初始化方法和构造方法 有区别? 构造方法作用申请空间,为对象基本属性初始化 , 初始化方法 对象复杂构造过程 , java语言建议将对象复杂构造过程单独抽取 初始化方法 )
在对象构造后,立即执行初始化init , 默认没有执行destroy 销毁方法
在Spring构造Bean对象过程中,有一个环节对Bean对象进行 后处理操作 (钩子函数) —– Spring 提供 BeanPostProcessor 接口
可以自定义类,实现 BeanPostProcessor 接口,配置到Spring容器中,在构造对象时,spring容器会调用接口中方法 。
(1)业界 AOP 实际上 OOP (面向对象编程 ) 延伸 —- OOP编程语言、 AOP设计思想 ;
(2)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
(3)横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ———- AOP 思想
Spring AOP 代理实现有两种: JDK动态代理和Cglib框架动态代理
(1)JDK动态代理
JDK API 内置 —- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 )
public class JdkProxyFactory implements InvocationHandler {
// 被代理对象
private Object target;
// 在构造方法对象时,传入被代理对象
public JdkProxyFactory(Object target) {
this.target = target;
}
// 创建代理
public Object createProxy() {
// 三个参数: 类加载器、 实现接口、 invocationhandler
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志!!!!!!");
// 调用目标真实方法
// target 被代理对象, args 方法参数 , method 被调用的方法
return method.invoke(target, args);
}
}
缺点: 使用Jdk动态代理,必须要求target目标对象,实现接口 ,如果没有接口,不能使用Jdk动态代理
(2)Cglib 动态代理
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理 (解决了 Jdk 只能对接口代理问题 )
下载网址: http://sourceforge.net/projects/cglib/files/
——- 在spring3.2版本 core包中内置cglib 类
public class CglibProxyFactory implements MethodInterceptor {
// 被代理目标对象
private Object target;
// 在构造工厂时传入被代理对象
public CglibProxyFactory(Object target) {
this.target = target;
}
// 创建代理对象方法
public Object createProxy() {
// 1、 创建Enhancer对象
Enhancer enhancer = new Enhancer();
// 2、 cglib创建代理,对目标对象,创建子类对象
enhancer.setSuperclass(target.getClass());
// 3、传入 callback对象,对目标增强
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("记录日志......");
// 按照JDK编程
return method.invoke(target, args);
}
}
Cglib 创建代理思想: 对目标类创建子类对象设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)设置 callback 实现增强代码 (类似 JDK代理 InvocationHandler )在cglib的callback函数中,要执行被代理对象的方法 method.invoke(target, args); 等价于 methodProxy.invokeSuper(proxy, args);
理解事务之前,先讲一个日常生活中最常干的事:取钱。
比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。
事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。
在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。
(1)原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
(2)一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
(3)隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
(4)持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
对Hibernate 进行事务管理
—- HibernateTransactionManager
平台事务管理器API
commit 提交事务
rollback 回滚事务
TransactionStatus getTransaction(TransactionDefinition) 根据事务定义信息获取事务状态信息
上面讲到的事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。
那么什么是事务属性呢?事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上
(1)ISOLATION_* 事务隔离级别
事务特性(ACID 原子性、一致性、隔离性、持久性 ) ,事务隔离性引发问题(脏读、不可重复读、 虚读 ), 数据库为了解决事务隔离性导致问题,引入四个隔离级别
DEFAULT 每种数据库提供默认隔离级别 mysql REPEATABLE_READ、oracle READ_COMMITTED
READ_UNCOMMITTED:引发所有隔离问题(脏读、不可重复读、虚读)
READ_COMMITTED:解决脏读, 引发(不可重复读、虚读)
REPEATABLE_READ : 解决脏读、不可重复读、 引发虚读
SERIALIZABLE :事务不存在并发性,阻止所有并发问题发生 (不推荐)
(2)PROPAGATION_* 事务的传播行为
传播行为不是数据库特性, 解决企业实际开发中事务隔离问题 —- 解决两个事务互相调用的问题
REQUIRED : 删除用户,删除订单, 使用同一个事务 ,删除订单必须存在事务
SUPPRTS :删除用户,删除订单, 使用同一个事务,如果删除用户没有事务,删除订单不使用事务
MANDATORY:删除用户,删除订单, 使用同一个事务,如果删除用户没有事务,删除订单直接抛出异常
REQUIRES_NEW: ATM取款后,打印凭条必须开启一个新的事务
NOT_SUPPORT:ATM取款后,打印凭条不使用事务运行
NEVER : 如何ATM取款,开启事务,打印凭条直接事务
NESTED : 嵌套事务 (只对DataSourceTransactionManager 起效), ATM取款和打印凭条处于同一个事务,在ATM取款后,设置SavePoint保存点,如果打印凭条出现问题,可以回滚到保存点
重点学习: REQUIRED、REQUIRES_NEW、NESTED
TIMEOUT_DEFAULT 超时时间
Read-Only 是否只读 (如果只读事务,不能执行 insert、update、delete操作)
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
可以发现这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。
1、 编程式事务,需要代码侵入 ,使用TransactionTemplate 模板类 (企业不用)
transactionTemplate.execute(new TransactionCallbackWithoutResult(){
T doInTransaction(){
// 数据库操作代码
}
});
doInTransaction方法只要发生异常,事务回滚,没有异常,事务提交
2、 声明式事务管理 ,无需要修改原来代码,只需要配置,为目标代码添加事务管理 , AOP底层实现 — 企业推荐
为何使用Spring?
Spring的IOC和AOP两大核心功能可以大大降低应用系统的耦合性、简化开发流程。
Spring框架技术可在不同层次上起作用,比如IOC管理普通的POJO对象、AOP增强了系统服务和其它组件(事务、MVC、JDBC、ORM和远程调用等)。Spring的一大特点就是基于接口编程,它是非侵入式的服务。用户端绑定接口使用Java EE服务,而非直接绑定服务,而且应用也可以使用不同的服务(hibernate、MyBatis等)。我们可以根据自己的需要,使用Spring的一部分服务,而不必使用完整的Spring系列项目。