笔记——spring基本使用(控制反转IOC、面向切面编程AOP、声明式事务,事务隔离级别、事务传播)
spring温习笔记
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。
Spring 的控制反转IOC、面向切面编程AOP等特性不多说。
本文核心内容:搭建一个Spring Demo
概要:想要启动spring这个大工厂,需要通过加载spring的核心配置文件类创建spring的核心类ApplicationContext,
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");这样spring就启动起来了。通过getBean方法可以手动获取Ban对象:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Student s=ac.getBean(Student.class);
这样可以看出使用spring之前需要先将spring的xml核心配置文件编辑好,这块的配置这里只做简单的配置使用,不进行深度研究。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!--通过该标签可以导入其他的xml文件 这样就可以将配置进行分开管理 -->
<import resource="aop.xml"/> <!--将aop的配置放到了该xml文件中 -->
<import resource="tx.xml"/> <!--将关于事务的配置放到该xml文件中 -->
<!-- 扫描Component组件 -->
<context:component-scan base-package="com"/>
<context:component-scan base-package="haha"/>
</beans>
关于控制反转IOC:将我们平时对对象的创建和管理交给spring这个大工厂,由他在我们需要的时候给我创建并注入给我们,
所以关于IOC的另一个说法就是D依赖注入,我们使用的对象需要依赖spring来注入到程序中,来做到集中管理,降低耦合的作用。
在使用这一特性时要让spring知道需要管理那些类和注入到哪里,平时常用注解的方式来配置,注解的方式感觉便捷很多,
在xml中开启组件扫描spring会自动扫描"com"包下的所有组件(Component、Controller、Service、Repository)
添加了注解的类会被spring管理,在需要使用的地方添加声明一个该对象的引用,在该属性上添加注入的注解(@Autowired、@Resource)两者之间的区别:
Autowired是自动注入,自动从spring的上下文找到合适的bean来注入
Resource用来指定名称注入
Qualifier和Autowired配合使用,指定bean的名称
Service,Controller,Repository分别标记类是Service层类,Controller层类,数据存储层的类,spring扫描注解配置时,会标记这些类要生成bean。
Component是一种泛指,标记类是组件,spring扫描注解配置时,会标记这些类要生成bean。
上面的Autowired和Resource是用来修饰字段,构造函数,或者设置方法,并做注入的。而Service,Controller,Repository,Component则是用来修饰类,标记这些类要生成bean。
import org.springframework.stereotype.Component;
@Component
public class TestComponentScan {
private String tname="DingZuoHeng";
public TestComponentScan(){}
//private TestComponentScan(){}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
}
该类为需要被spring管理的component组件。
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class Student {
@Resource
TestComponentScan testComponentScan;
public void haveClass(){
System.out.println("Student类中的haveClass方法执行。。。"+testComponentScan.getTname());
}
}
将上述组件注入到Student类中,启动spring并运行haveClass方法就可以看到控制台输出被注入类的信息。
以上就是spring IOC注解方式的简单使用。下面为AOP简单使用:
aop的相关术语:
1 增强(Before、After、Around等) 要额外添加的功能/ 提取出来的重复功能(体现为一个方法)
2 切面(Aspect) 组织增强的地方 放到代码里就是个类
3 连接点(pointcut) 可以添加增强的地方放 spring里就是方法
4 切入点 被添加了增强的连接点
5 织入 添加增强的过程
6 目标 要添加增强的地方
springAop的开发步骤 :
1 导包 spring需要额外的aop支持 aspectJ
2 编写 切面代码
3 编写 配置文件 或注解
导入依赖后、编写切面以及增强、其实就是编写一个类然后在该类里面编写方法。
写好后可以直接在增强上添加注解(例如:@Before("execution(* com.*.Student.have*(..))")),或者在配置文件中
添加:
<aop:aspectj-autoproxy/> <-- 开启注解方式的Aspect -->
<aop:config>
<aop:aspect ref="aspect2" >
<aop:before method="testAspectbefore" pointcut="execution(void com.entity.*.*(..))"/>
<aop:after method="testAspectafter" pointcut="execution(void com.entity.*.*(..))"/>
</aop:aspect>
</aop:config>
切入点表达式
execution ( 表达式 )
表达式 :通配方法: * 代表所有返回值 类的全名一直到方法名(..) 代表所有参数
例:execution (* com.oracle.aop.Student.haveClass(..))
AOP的基本使用就到这里了。在这里在提一个必然会使用的spring声明式事务管理,它是基于AOP技术来实现了。
声明式事务:基于AOP实现(动态代理方式织入事务、提交/回滚事务),只需要要配置文件中配置好事务规则(tx及aop配置或使用@Transactional注解),注解方式开发简洁推荐使用。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost/test"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
<property name="maxPoolSize" value="10"/>
<property name="initialPoolSize" value="2"/>
</bean>
在xml中配置一个bean,让spring的事务平台管理类加入到容器中,并提供数据源,这里以c3p0来演示。因使用注解的便利性
大多数时都是使用@Transactional注解 ,在使用该注解时需要在配置中添加如下:
<tx:annotation-driven transaction-manager="transactionManager"/> 来开启对事务注解
关于事务的其他需要了解的:
事务隔离级别(与数据库四个级别一致)
1> TransactionDefinition.ISOLATION_DEFAULT # 这是默认值,表示使用底层数据库的默认隔离级别。大部分数据库通常默认是:READ_COMMITTED读已提交;
2> TransactionDefinition.ISOLATION_READ_UNCOMMITTED # 一个事务可以读取另一个事务修改但还没有提交的数据。
存在问题:该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
3> TransactionDefinition.ISOLATION_READ_COMMITTED # 一个事务只能读取另一个事务已经提交的数据。可以防止脏读,这也是大多数情况下的推荐值。
4> TransactionDefinition.ISOLATION_REPEATABLE_READ # 一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。可以防止脏读和不可重复读。
5> TransactionDefinition.ISOLATION_SERIALIZABLE # 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,可以防止脏读、不可重复读以及幻读。
但是这将严重影响程序的性能。通常情况下也不会用到该级别。
脏读(Dirty read):脏读发生在一个事务读取了被另一个事务改写但还未提交的数据时。如果这些改变在稍后被回滚,那么之前的事务读取的到数据就是无效的。
不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但每一次的查询结果不同时。这通常是由于另一个并发的事务在两次查询之间更新了数据。
幻读(Phantom read):幻读是一个事务读取几行记录后,另一个事务插入了一些记录,幻读就发生了。在后来的查询中第一个事务就会发现有一些原来没有的额外的记录。
事务传播行为(TransactionDefinition)
1> PROPAGATION_MANDATORY # 该方法必须运行在一个事务中。如果当前事务不存在则抛出异常。
2> PROPAGATION_NESTED # 如果当前存在一个事务,则该方法运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交和回滚。如果当前不存在事务,则开始一个新的事务。各厂商对这种传播行为的支持参差不齐,使用时需注意。
3> PROPAGATION_NEVER # 当前方法不应该运行在一个事务中。如果当前存在一个事务,则抛出异常。
4> PROPAGATION_NOT_SUPPORTED # 当前方法不应该运行在一个事务中。如果一个事务正在运行,它将在该方法的运行期间挂起。
5> PROPAGATION_REQUIRED # 该方法必须运行在一个事务中。如果一个事务正在运行,该方法将运行在这个事务中。否则,就开始一个新的事务。
6> PROPAGATION_REQUIRES_NEW # 该方法必须运行在自己的事务中。它将启动一个新的事务。如果一个现有的事务正在运行,将在这个方法的运行期间挂起。
7> PROPAGATION_SUPPORTS # 当前方法不需要事务处理环境,但如果一个事务已经在运行的话,这个方法也可以在这个事务里运行。