1、Spring框架
- Spring Core spring的核心功能: IOC容器, 解决对象创建及依赖关系
- Spring Web Spring对web模块的支持, spring mvc模式
- Spring DAO Spring 对jdbc操作的支持 【JdbcTemplate模板工具类】
- Spring ORM spring对orm的支持:可以与mybatis整合
- Spring AOP 切面编程
2、spring是单例还是多例
- singleton 作用域
当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例。 - Prototype
prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的 getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。 - request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例:request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置: - session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
3、SpringIOC 容器
容器创建对象
1) 调用无参数构造器
2) 带参数构造器
3) 工厂创建对象
工厂类,静态方法创建对象
工厂类,非静态方法创建对象
给对象的属性赋值
- 通过构造函数
- 通过set方法给属性注入值
- p名称空间
- 注解
@Resource与@Autowired区别
1、@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,
3、@Resource(这个注解属于J2EE的),默认安照名称进行装配,名称可以通过name属性进行指定, 如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配
4、AOP编程
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码。
@Aspect 指定一个类为切面类
@Pointcut("execution(* com.itmayiedu.service.UserService.add(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
动态代理
1、JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
2、CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
3、 CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
5、spring事务
事务应该在Service层统一控制。
1、Spring 事务的核心接口
Spring 通过一个名为spring-tx-4.3.6-RELEASE 的JAR包来管理事务,在这个JAR包中的org.Springframework.transaction 包中包含了三个接口文件:
- PlatformTramsactionManager 主要用于管理事务,包括获取事务的状态、提交事务和回滚事务;
- TramsactionDefinition 该接口是事务定义的对象,包括了获取事务的名称、隔离级别、事务的传播行为、超时时间、事务是否只读等;
- TramsactionStatus 该接口是事务的状态,描述了某一个时间点事务状态信息,包括刷新事务、获取是否存在保存点、是否是新事务、是否回滚、设置事务回滚。
2、事务管理方式有2种
一种是传统的编程序事务管理,即通过代码来管理事务的开始、执行和异常以及回滚,一种是声明式管理,即通过配置文件的方式,原理是通过AOP技术实现,我们在实际开发过程中推荐使用声明式事务管理,效率会大大提升,因为只需要通过配置即可。
2.1 编程式事务控制
自己手动控制事务,就叫做编程式事务控制。
Jdbc代码:Conn.setAutoCommite(false); // 设置手动控制事务
Mybatis代码:Session.beginTransaction(); // 开启一个事务
细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制
(比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void add(String name, Integer age) {
String sql = "INSERT INTO users(NAME, age) VALUES(?,?);";
int update = jdbcTemplate.update(sql, name, age);
System.out.println("updateResult:" + update);
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void add() {
userDao.add("lisi", 18);
int i=1/0;//可能会发生异常
userDao.add("link", 19);
}
}
public class UserTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.add();
}
}
@Component
public class TransactionUtils {
// 事物管理器
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
public TransactionStatus begin() {
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
return transaction;
}
public void commit(TransactionStatus transaction) {
dataSourceTransactionManager.commit(transaction);
}
public void rollback(TransactionStatus transaction) {
dataSourceTransactionManager.rollback(transaction);
}
}
- bean.xml (Spring务管理配置)
<!-- 1. 数据源对象: C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!-- 2. JdbcTemplate工具类实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事物 -->
<bean id="DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
@Aspect
@Component
public class Aop {
@Autowired
private TransactionUtils transactionUtils;
private TransactionStatus begin;
@Before("execution(* com.link.service.UserService.add(..))")
public void bean(){
System.out.println("......前置通知......");
}
@After("bean")
public void commit(){
System.out.println(".......后置通知......");
}
@AfterReturning("bean")
public void afterRun(){
System.out.println(".......运行通知......");
}
@AfterThrowing("bean")
public void afterThrowing(){
System.out.println(".......异常通知......");
transactionUtils.rollback(begin);
}
@Around("bean")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
begin = transactionUtils.begin();
System.out.println("我是环绕通知-前");
// 放行实际方法
proceedingJoinPoint.proceed();
System.out.println("我是环绕通知-后");
transactionUtils.commit(begin);
}
}
2.2 声明式事务控制
Spring提供了对事务的管理, 这个就叫声明式事务管理。
Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可;不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。
Spring声明式事务管理,核心实现就是基于Aop。
粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。
(因为aop拦截的是方法。)
xml方式
<!-- 1. 数据源对象: C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!-- 2. JdbcTemplate工具类实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事物 -->
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!—配置事物增强-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="*" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
<aop:config>
<aop:pointcut expression="execution(* com.link.service.*.*(..))"
id="pt" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
</aop:config>
注解方式
@Transactional
public void add() {
try {
userDao.add("lisi", 18);
int i = 1 / 0;
userDao.add("yushengjun", 19);
} catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
3、事务特性
3.1 传播七种行为
Propagation(key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。)有以下选项可供使用:
• PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
• PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
• PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
• PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
• PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
• PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
@Transactional(
readOnly = false, // 读写事务
timeout = -1, // 事务的超时时间不限制
noRollbackFor = ArithmeticException.class, // 遇到数学异常不回滚
isolation = Isolation.DEFAULT, // 事务的隔离级别,数据库的默认
propagation = Propagation.REQUIRED // 事务的传播行为
)
事务传播行为:
Propagation.REQUIRED
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务, 就会加入当前的事务;
Propagation.REQUIRED_NEW
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行。
public enum Propagation {
REQUIRED(0),//表示当前方法必须运行在一个事务环境中,如果存在就直接使用,否则开启一个新的事务执行该方法
SUPPORTS(1),//如果当前方法处于事务环境中则使用,否则不使用事务
MANDATORY(2),//表示该方法的线程必须在事务中否则抛出异常
REQUIRES_NEW(3), //要求在新事务中执行,如果已经在事务中了则先暂停然后启动新事务执行,如果不在则启动一个新事务后执行
NOT_SUPPORTED(4), //不支持当前事务,总是以非事务状态执行,如果调用该方法的线程处于事务中泽先暂停然后执行
NEVER(5), //不支持当前执行的方法在事务中,如果在抛出异常
NESTED(6); //即便当前执行的方法在事务中也会启动一个新事务,然后执行该方法
private final int value;
}
@Transactional 只能应用到 public 方法才有效
这是因为在使用 Spring AOP 代理时,Spring 在调用 TransactionInterceptor 在目标方法执行前后进行拦截之前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 通过这个类获取 @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法
3.2 隔离级别
public enum Isolation {
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
private final int value;
}