文章目录
Spring提供了JavaEE每一层的解决方案,Spring是Java EE的全栈式框架。
Spring的优势
Spring除了不能帮助我们系统业务逻辑,其余的部分都能帮助我们简化开发。
- Spring低浸入、低耦合地根据配置文件创建及组装对象间的关系。
- Spring面向切面编程,日志记录、性能统计、安全控制。
- 强大的声明式事务管理。
- 提供了与第三方优秀框架的整合(Hibernate、JPA),自己也有一套JDBC模板方便访问数据库。
- 提供了与第三方Web(Struts1/2、JSF)整合,自己也有一套SpringMVC。
- 方便的与Java Mail、任务调度、缓存框架技术整合,降低开发难度。
Spring框架架构
Core Container(核心容器)包含Beans、Core、Context、SpELl模块。
Data Access、Integration层包含JDBC、ORM、JMS、OXM、Transactions模块。
Web层包含Web、WebSocket、Servlet、Porlet模块
AOP提供符合AOP联盟标准的面向切面实现。
Test支持使用TestNG和Junit组件测试。
一、IOC
IOC容器
原理:
1. 通过Resource对象加载配置文件
2. 解析配置文件,得到指定名称的Bean
3. 解析Bean元素,id为bean的名称,class反射得到实例
4. getBean返回实例对象
DI:依赖注入(注入依赖)
IOC容器是如何知道哪些是它应该管理的对象呢?
这时候需要配置文件,IOC容器通过读取配置文件的配置元数据。
元数据的配置的三种方式:
- xml
- Annotation 注解
- Java-base Java代码
使用BeanFactory有延迟初始化类的特性,从哪可以看出呢?
Spring先创建容器,等到客户端获取某个对象的时候再去创建对象。
实例:
使用ApplicationContext没有延迟,在初始化容器的时候就开始创建bean.–推荐使用
实例化方式
- 构造器实例化–推荐(保证无参数构造器)
- 静态工厂实例化
- 实例工厂方法
- 实现FactoryBean接口实现
bean作用域
- singleton单例(默认)–常用
- prototype多例(struts2的action)
- request web开发中将bean放入request
- session web开发中将bean放入session
- globalSession Porlet环境下,分布式系统存在session(单点登录)
- application 将单个bean定义的作用域限定为ServletContext的生命周期。 仅在可感知网络的ApplicationContext上下文中有效。
- websock 将单个bean定义的作用域限定为ServletContext的生命周期。 仅在可感知网络的websock 上下文中有效。
bean的生命周期
- 启动Spring容器
- 通过Bean对象的构造器创建Bean
- 注入属性
- 调用初始化方法init-method
- 我们使用
- 调用销毁方法destroy-method
- Spring容器销毁
DI
注入依赖。注入bean的属性值。
方式一:setter方法注入
方式二:构造器注入
XML配置(了解)
- byName
- 通过构造器
<bean class="com.itxin.spring.xml.Person" autowire="constructor"/>
setter注入
- 对于变量
- 对于对象
- 对于集合
构造器注入
bean元素继承
placeholder (连接池常用)
注解
@Autowired Spring官方提供,字段或者setter方法上,spring3.0之前需要手动配置解析器 找不到依赖(注入null)可配置不报错
@Resource JavaEE规范,作用跟Autowire相同,找不到依赖报错
@value 注入简单类型,常量,不能掉{}
@Component 用在类名上,默认bean的id类名首字母小写。需要配置IOC注解解析器。
Java代码配置
二、AOP
先来说说代理模式
静态代理:在程序运行前就已经存在代理类的字节码文件。
动态代理:动态代理类在程序运行前由JVM通过反射动态生成,不存在字节码文件。
如何实现动态代理?
- JDK动态代理
- CGLIB动态代理
package com.itxin.spring.proxy;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.springframework.cglib.proxy.Enhancer;
import lombok.Setter;
/**
* CGLIB动态代理
*
* @author Administrator
*
*/
public class EmployeeAdviceCGLIB implements org.springframework.cglib.proxy.InvocationHandler {
@Setter
private Object obj;
/**
* 具体的增强细节
*/
@Override
public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
return null;
}
/**
* 创建代理对象
*
* @param <T>真实对象类型
* @return
*/
public <T> T getProxyObject() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());// 继承要增强的那个类
enhancer.setCallback(this);
return (T) enhancer.create();// 创建代理对象
}
}
两者之间的区别?
JDK动态代理必须提供接口
CGLIB原理:自己的真实对像的代理类实现真实类,把原来需要增强的方法覆盖重写实现增强。所以它不需要接口。
术语 | 翻译 | 解释 |
---|---|---|
Jionpoint | 连接点 | 被拦截到需要增强的方法 |
Pointcut | 切入点 | 哪些包中的哪些类中的哪些方法(连接点的集合) |
Advice | 增强 | 当拦截到Jionpoint后,在方法执行的什么时期。(前置增强、后置增强、异常增强、最终增强、环绕增强) |
Aspect | 切面 | Pointcut+Advice,去哪些地方+在什么时候+做什么增强 |
Target | 目标对象 | 被代理的目标对象 |
Weaving | 织入 | 把Advice加到Target之后,创建出Proxy对象的过程 |
Proxy | 代理类 | 一个类被AOP织入增强后,产生的代理类 |
Pointcut表达式
通配符*:表示一个单词,匹配任意部分
通配符…:全限定名中的和方法参数,分别表示子包和0-n个参数
<!-- 对com.itxin.spring.service包中,所有以Service结尾的方法增强+ -->
execution(* com.itxin.spring.service.*Service.*(..))
使用注解方式配置切面
@Component
@Aspect
public class TxAdvice {
@Pointcut("execution(* com.itxin.spring.service.*Service.*(..))")
public void txAdvice() {
}
}
注意使用注解方式需要配置AOP的解析器。
三、DAO
JdbcTemplate是 JDBC 核心包中的中心 class。它处理资源的创建和释放,帮助您避免 common 错误,例如忘记关闭连接。它执行核心 JDBC 工作流的基本任务(例如语句创建和执行),留下 application code 以提供 SQL 并提取结果。 JdbcTemplate class:
运行 SQL 查询
更新 statements 和存储过程 calls
对ResultSet实例执行迭代并提取返回的参数值。
捕获 JDBC exceptions 并将它们转换为org.springframework.dao包中定义的通用的,更具信息性的 exception 层次结构。 (见一致的 Exception 层次结构 .)
当您为 code 使用JdbcTemplate时,您只需要实现回调接口,为它们提供明确定义的 contract。给定JdbcTemplate class 提供的Connection,PreparedStatementCreator回调接口创建一个预准备语句,提供 SQL 和任何必要的参数。 CallableStatementCreator接口的 true 也是如此,它创建了可调用的 statements。 RowCallbackHandler接口从ResultSet的每一行中提取值。
您可以通过使用DataSource reference 直接实例化在 DAO implementation 中使用JdbcTemplate,也可以在 Spring IoC 容器中对其进行配置,并将其作为 bean reference 提供给 DAO。
@Repository (1)
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
@Autowired (2)
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource); (3)
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
事务引出
转账案列:转账操作,转入+转出,以前程序这样正常执行
- 开启事务
- 转入
- 提交事务
转出正常操作
- 开启事务
- 转出
- 提交事务
如果在这两个操作之前出现异常,钱就莫名少了,需要把这两个操作绑定在一起。也就是说,这两个操作根本就不在同一个事务中。
事务
概念:事务是一系列操作组成的工作单元,该工作单元的操作是不可分割的,要么所有操作都做,要么都不做。
名词 | 解释 |
---|---|
Atomicity原子性 | 事务是不可分割的最小单元。事务内的操作要么都做,要么都不做。 |
Consistency一致性 | 数据完整性约束没有被破坏。 |
Isolation隔离性 | 多个事务处于并发访问同一个数据库资源时,事务之间相互影响程度。 |
Durability持久性 | 事务一旦执行成功,改变不可逆 |
数据并发导致的五类问题
问题类型 | 原因+效果 |
---|---|
第一类丢失更新 | 两个事务更新相同数据,如果一个事务提交,另一个事务回滚,第一个事务的更新将被回滚。 |
脏读 | 第二个事务查询到第一个事务未提交的更新数据,第二个事务根据该数据执行,但第一个事务回滚,第二个事务操作脏数据。 |
虚读 | 一个事务查询到了另一个事务已经提交的新数据,导致多次查询年数据不一致。 |
不可重复读 | 一个事务查询到另一个事务已经修改的数据,导致多次查询数据不一样。 |
第二类丢失更新 | 多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务的修改。 |
Spring提供的事务管理
事务的传播规则
- 情况一:需要遵从当前事务
REQUIRED:必须存在一个事务,如果当前存在一个事务,则加入到该事务中,否则,新建一个事务;----使用较多
SUPPORTS:支持当前事务。如果当前存在事务,则使用改事务,否则,以非事务形式运行。
MANDAT:强制的,必须存在事务,如果当前存在事务,使用,否则,非法的事务状态异常(IllegalTranactionStatusExcetion)
- 情况二:不存在当前事务的
REQUIRES_NEW:不管当前是否存在事务,必须是一个新的事务。–使用较多。
NOT_SUPPORTD:以非事务方式执行,如果当前存在事务,把当前事务挂起(暂停)
NEVER:不支持事务,如果当前存在事务,抛出异常。- 情况三:寄生事务(外部事物、内部事务、嵌套事务)
NESTED: 寄生事务:如果当前存在事务,则在内部事务执行
不存在事务,则创建一个新的事务。寄生事务可以通过数据库savePoint来实现,寄生事务可以回滚,但是他的回滚不影响外部事务,但是外部事物的回滚会影响寄生事务。
寄生事务并不是所有事务管理器都支持,hibernate默认不支持,需要手动开启。jdbc和mybatis的事务管理器DateSourceTransaction默认支持。
- 情况三:寄生事务(外部事物、内部事务、嵌套事务)