Spring进阶
基于AspectJ的AOP开发
AspectJ简介
-
是一个基于Java语言的AOP框架
-
Spring2.0以后新增了对AspectJ切点表达式支持
-
@AspectJ通过JDK5注解技术,允许直接在Bean类中定义切面
-
需要导入Spring AOP和AspectJ相关jar包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51<!-- 引入spring基本开发包-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<!--加载aspectj的包-->
<!-- aspectj 基于aop-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
</dependencies> -
创建配置文件
1
2
3
4
5
6
7
8
9
10
11
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
<!--开启AspectJ的注解开发,自动代理-->
<aop:aspectj-autoproxy/>
</beans>
AspectJ提供的通知类型
-
@Before 前置通知,相当于BeforeAdvice
可以在方法中传入JoinPoint对象,获得切点信息
1
2
3
4
public void before(JoinPoint joinPoint){
System.out.println("前置通知==================="+joinPoint);
} -
@AfterReturning 后置通知,相当于AfterReturningAdvice
通过returning属性,定义方法返回值作为参数
1
2
3
4
public void afterReturning(Object result){
System.out.println("后置通知========="+result);
} -
@Around 环绕通知,相当于MethodInterceptor
返回值是目标代理方法执行返回值
通过ProceedingJoinPoint可以调用拦截目标方法执行
若不调用ProceedingJointPoint的proceed方法,则目标方法会被拦截
1
2
3
4
5
6
7
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知");
Object obj = joinPoint.proceed(); //执行目标方法
System.out.println("环绕后通知");
return obj;
} -
@AfterThrowing 异常抛出通知,相当于ThrowAdvice
通过设置throwing属性,可以设置发生异常对象参数
1
2
3
4
public void afterThrowing(Throwable e){
System.out.println("抛出异常通知"+e.getMessage());
} -
@After 最终final通知,不管是否异常,通知都会执行
1
2
3
4
public void after(){
System.out.println("最终通知==================");
}
切入点表达式的定义
-
通过execution函数,可以定义切点的方法切入
语法:-execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
入门案例
-
切面类
1
2
3
4
5
6
7
8/* 切面类 */
public class MyAspectAnno { // 返回类型 方法 传入值
public void before(){
System.out.println("前置通知===================");
}
} -
测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SpringDemo1 {
private ProductDao productDao;
public void demo1(){
productDao.save();
productDao.update();
productDao.delete();
productDao.findAll();
productDao.findOne();
}
} -
配置文件
1
2
3
4
5<!--目标类-->
<bean id="productDao" class="com.imooc.aspectJ.demo1.ProductDao"/>
<!-- 定义切面-->
<bean class="com.imooc.aspectJ.demo1.MyAspectAnno"/>
切点命名
-
使用@Pointcut进行定义
-
切点方法:private void 无参数方法,方法名为切点名
-
当通知多个切点时,可以使用"||”进行连接
1
2
3
4
5
6
7
8
9
private void myPointcut1(){
}
public void before(JoinPoint joinPoint){
System.out.println("前置通知===================" + joinPoint);
}
AspectJ的xml方式开发AOP-环境搭建
-
配置文件(以前置通知为例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<!--xml配置方式完成AOP开发-->
<!--配置目标类-->
<bean id="customerDao" class="com.imooc.aspectJ.demo2.CustomerDaoImpl"/>
<!-- 配置切面类-->
<bean id="myAspectXml" class="com.imooc.aspectJ.demo2.MyAspectXml"></bean>
<!--aop相关配置-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pointcut1" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.save(..))"/>
<!--配置AOP切面-->
<aop:aspect ref="myAspectXml" >
<!--配置前置通知-->
<aop:before method="before" pointcut-ref="pointcut1"/> <!--before为方法名-->
</aop:aspect>
</aop:config>
-
myAspectXml类
1
2
3
4//前置通知
public void before(JoinPoint joinpoint){
System.out.println("xml方式前置通知"+joinpoint);
}
-
测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SpringDemo2 {
private CustomerDao customerDao;
public void demo1(){
customerDao.save();
customerDao.update();
customerDao.delete();
customerDao.findOne();
customerDao.findAll();
}
}提示:其他通知可以参考注解方法和xml方法完成,不作过多举例
JDBC的Template
搭建项目
-
Maven
- Mysql驱动
- Spring组件(core\beans\context\aop)
- JDBC Template(jdbc\tx)
-
Spring配置
- 数据源
- JDBC Template
-
配置pom.xml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41<properties>
<spring.version>4.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--jdbc template-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies> -
配置spring.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/selection_course?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
JDBC Template基本使用
-
execute方法
1
2
3
4
5public void testExecute(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");
jdbcTemplate.execute("create table user1(id int,name varchar(20))");
} -
update与batchUpdate方法
- int update(String sql, Object[] args);
- int update(String sql, Object… args);
1
2
3
4
5
6
7
8
9public void testUpdate(){
String sql = "insert into student(name,sex) values(?,?)";
jdbcTemplate.update(sql,new Object[]{"张三","男"});
}
// 另一种写法
public void testUpdate2(){
String sql = "update student set sex=? where id = ?";
jdbcTemplate.update(sql,"女",1); //此处没有用数组
}- int[] batchUpdate(String[] sql);
- int[] batchUpdate(String sql, List<Object[]> args);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public void testBatchUpdate(){
String[] sqls={
"insert into student(name,sex) values('关于','女')",
"insert into student(name,sex) values('刘备','男')",
"update student set sex='男' where id = 1"
};
jdbcTemplate.batchUpdate(sqls);
}
// 另一种写法
public void testBatchUpdate2(){
String sql = "insert into selection(student,course) values(?,?)";
List<Object[]> list = new ArrayList<Object[]>();
list.add(new Object[]{3,1001});
list.add(new Object[]{3,1003});
jdbcTemplate.batchUpdate(sql,list);
} -
query与queryXXX方法
-
call方法
Spring的事务管理
Java事务导引
-
什么是事务
- 事务是正确执行一系列的操作,使得数据库从一种状态转换成另一种状态
-
事务原则是什么(ISO/IEC所制定的ACID原则)
- 原子性(Atomicity),即不可分割性
- 一致性(Consistency)
- 隔离性(Isolation),事务提交前,结果不应该显示给任何其他事务
- 持久性(Durability),事务提交后结果将永久保存在数据库中
-
Java事务类型
- JDBC事务:用Connection对象控制,包括手动和自动模式
- JTA事务:与实现无关的,与协议无关的API
- 容器事务
Spring事务接口
1 | // Spring事务状态接口: |
Spring事务属性定义
- 数据读取类型
- 脏读(事务还没提交,提前读取)
- 不可重复读(两次读取的数据不一致)
- 幻读(事务不是独立执行时发生的一种非预期现象)
- 事务隔离级别
- 定义了一个事务可能受其他并发事务影响的程度
- 事务传播行为
- 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播
- 事务是否只读
- 利用数据库“只读”属性,进行特定优化处理
- 事务超时
- 是一个计时器,在特定时间内没有执行完毕,则进行回滚而不是等待
- 事务回滚
- 默认情况下,事务只有遇到运行期异常才会回滚,遇到检查型异常时不回滚
编程式事务管理
- 事务管理器(PlatformTransactionManager)方式
- 核心类:Spring事务管理的三个接口类及JdbcTemplate类
- 模板事务(TransactionTemplate)的方式
- 主要工具为JdbcTemplate类