Spring框架的AOP技术(注解方式)
1、创建JavaWeb项目,引入具体的开发的jar包
引入Spring框架开发的基本开发包
再引入Spring框架Spring框架的AOP的开发包
spring的传统AOP的开发的包
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
aspectJ的开发包
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
2、创建Spring的配置文件,引入具体的AOP的schema约束
"http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
http:
http:
3、创建包结构,编写具体的接口和实现类
my.demo1
CustomerDao 接口
CustomerDaoImpl 实现类
4、将目标类配置到spring中
"customerDao" class="my.demo1.CustomerDaoImpl"/>
5、定义切面类
添加切面和通知的注解
Aspect 定义切面类的注解
通知类型(注解的参数是切入点的表达式)
Before 前置通知
AfterReturing 后置通知
Around 环绕通知
After 最终通知
AfterThrowing 异常抛出通知
代码
@Aspect
public class MyAspectAnno {
@Before(value="execution(public * my.demo1.CustomerDaoImpl.save())")
public void log() {
System.out.println("记录");
}
}
6、在配置文件中定义切面类
"myAspectAnno" class="my.demo1.MyAspectAnno"/>
7、在配置文件中开启自动代理
8、测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
@Resource(name="customerDao")
private CustomerDao customerDao;
@Test
public void run1() {
customerDao.save();
customerDao.update();
}
}
通知类型
1、通知类型
Before 前置通知
AfterReturing 后置通知
Around 环绕通知(目标对象方法默认不执行,需要手动执行)
After 最终通知
AfterThrowing 异常抛出通知
2、配置通用的切入点
使用@Pointcut定义通用的切入点
@Before(value="MyAspectAnno.fun()")
public void log() {
System.out.println("记录");
}
@Pointcut(value="execution(public * my.demo1.CustomerDaoImpl.save())")
public void fun() {}
JDBC模版技术概述
1、Spring框架中提供了很多持久层的模版来简化编程,使用模版类编写程序会变得简单
2、提供了JDBC模版,Spring框架提供的
JdbcTemplate类
3、Spring框架可以整合Hibernate框架,也提供了模版类
HibernateTemplate类
JDBC的模版类
1、创建数据库的表结构
CREATE DATABASE spring_day03;
USE spring_day03;
CREATE TABLE t_account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money DOUBLE
);
2、引入开发的jar包
先引入IOC基本的6个jar包
再引入Spring-aop的jar包
最后引入JDBC模版需要的jar包
Mysql数据库的驱动包
Spring-jdbc.jar
Spring-tx.jar
3、测试代码(自己来new对象)
@Test
public void run1() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day03");
dataSource.setUsername("root");
dataSource.setPassword("123");
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource);
template.update("insert into t_account values (null,?,?)","ww",123);
template.update("insert into t_account values (null,?,?)","我的",123);
}
Spring框架来管理模版类
1、刚才是new的方式,现在应该交给Spring框架来管理
2、修改:
Spring管理内置的连接池
"dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
"driverClassName" value="com.mysql.jdbc.Driver">
"url" value="jdbc:mysql://localhost:3306/spring_day03">
"username" value="root">
"password" value="123">
Spring管理模版类
"jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
"dataSource" ref="dataSource">
测试程序
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdabcTemplate;
@Test
public void run1() {
jdabcTemplate.update("insert into t_account values (null,?,?)","我的",123);
}
}
框架管理开源的连接池
1、管理DBCP连接池
先引入DBCP的2个jar包
com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
编写配置文件
"dataSource" class="org.apache.commons.dbcp.BasicDataSource">
"driverClassName" value="com.mysql.jdbc.Driver">
"url" value="jdbc:mysql://localhost:3306/spring_day03">
"username" value="root">
"password" value="123">
2、管理c3p0连接池
引入c3p0的jar包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
配置文件
"dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
"driverClass" value="com.mysql.jdbc.Driver">
"jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day03">
"user" value="root">
"password" value="123">
JDBC模版的基本操作
@Test
public void run1() {
jdbcTemplate.update("insert into t_account values (null,?,?)","你的12",123);
}
@Test
public void run2() {
jdbcTemplate.update("update t_account set name=? where id=?","我得天天",1);
}
@Test
public void run3() {
jdbcTemplate.update("delete from t_account where id=?",1);
}
@Test
public void run4() {
Account ac = jdbcTemplate.queryForObject("select * from t_account where id=?", new BeanMapper(),2);
System.out.println(ac);
}
@Test
public void run5() {
List list = jdbcTemplate.query("select * from t_account",new BeanMapper());
System.out.println(list);
}
}
class BeanMapper implements RowMapper{
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account ac = new Account();
ac.setId(rs.getInt("id"));
ac.setName(rs.getString("name"));
ac.setMoney(rs.getDouble("money"));
return ac;
}
}
事务的回顾
1、事务:指的是逻辑上一组操作,组成这个事务的各个执行单元,要么一起成功,要么一起失败
2、事务的特性
原子性
一致性
隔离性
持久性
3、如果不考虑隔离性,引发安全性问题
读问题
脏读
不可重复读
虚读
写问题
丢失更新
4、解决安全性问题
读问题解决,设置数据库隔离级别
写问题解决可以使用 悲观锁和乐观锁的方式解决
Spring框架的事务管理相关的类和API
1、PlatformTransactionManager接口 --平台事务管理器(真正管理事务的类)该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类
2、TransactionDefinition接口 --事务定义信息(事务的隔离级别,传播行为,超时,只读)
3、TransactionStatus接口 --事务的状态
4、上述对象之间的关系,平台事务管理器真正管理事务对象,根据事务定义的信息TransactionDefinition进行事务管理,在管理事务中产生一些状态,将状态记录到TransactionStatus中
5、PlatformTransactionManager接口中实现类和常用的方法
接口的实现类
如果使用的是Spring的JDBC模版或者MyBatis框架,需要选择DataSourceTransactionManager实现类
如果使用的是Hibernate的框架,需要选择HibernateTransactionManager实现类
常用的方法
void commit(TransactionStatus status)
TransactionStatus.getTransaction(TransactionDefinition definition)
void rollback(TransactionStatus status)
6、TransactionDefinition
事务隔离级别的常量
static int ISOLATION_DEFAUTL 采用数据库的默认隔离级别
static int ISOLATION_READ_UNCOMMITTED
static int ISOLATION_READ_COMMITTED
static int ISOLATION_REPEATABLE_READ
static int ISOLATION_SERIALIZABLE
事务的传播行为常量(不用设置,使用默认值)
解决的是业务层之间的方法调用
PROPAGATION_REQUIRED(默认值) A中有事务,使用A中的事务,如果没有,B就会开启一个新的事务,将A包含进来(保证A,B在同一个事务中)
PROPAGATION_SUPPORTS A中有事务,使用A中的事务,如果没有,那么B也不使用事务
PROPAGATION_MANDATORY A中有事务,使用A中的事务,如果没有,那么抛出异常
PROPAGATION_REQUIRED_NEW A中有事务,将A中的事务挂起,B创建一个新的事务(保证A,B没有在一个事务中)
PROPAGATION_NOT_SUPPORTED A中有事务,将A中的事务挂起
PROPAGATION_NEVER A中有事务,那么抛出异常
PROPAGATION_NESTED 嵌套事务,当A执行之后,会在这个位置设置一个保存点,如果B没有问题,执行通过,如果B出现异常,运行客户根据需求回滚(选择回到保存点或是最初始状态)
搭建事务管理转账案例的环境(简化开发,以后DAO可以继承JdbcDaoSupport类)
1、创建WEB工程,引入需要的jar包
IoC的6个包
AOP的4个包
C3P0的一个包
MySQL的驱动包
JDBC模版2个包
整合JUNIT测试包
2、引入配置文件
引入log4j.properties
引入applicationContext.xml
"dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
"driverClass" value="com.mysql.jdbc.Driver">
"jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day03">
"user" value="root">
"password" value="123">
3、创建对应的包结构和类
my.demo1
AccountDao.java
AccountDaoImpl.java
AccountService.java
AccountServiceImpl.java
4、引入Spring的配置文件,将类配置到Spring中
"accountService" class="my.demo1.AccountServiceImpl">
"accountDao" class="my.demo1.AccountDaoImpl">
5、业务层注入DAO,在DAO中注入JDBC模版(简化开发,以后DAO可以继承JdbcDaoSupport类)
"accountService" class="my.demo1.AccountServiceImpl">
"accountDao" ref="accountDao">
"accountDao" class="my.demo1.AccountDaoImpl">
"dataSource" ref="dataSource">
6、编写DAO和Service中的方法
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
public void outMoney(String out, double money) {
this.getJdbcTemplate().update("update t_account set money=money-? where name=?",money,out);
}
public void inMoney(String in, double money) {
this.getJdbcTemplate().update("update t_account set money=money-? where name=?",money,in);
}
}
7、测试程序
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
@Resource(name="accountService")
private AccountService accountService;
@Test
public void run1() {
accountService.pay("你的", "我的", 12);
}
}
事务管理的分类
1、Spring的事务管理的分类
Spring的编程式事务管理(不推荐使用)
通过手动编写代码的方式完成事务的管理(不推荐)
Spring的声明式事务管理(底层采用AOP的技术)
通过一段配置的方式完成事务的管理
事务管理之编程式的事务管理
1、Spring为了简化事务管理的代码,提供了模版类TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模版类即可
2、具体步骤
配置一个事务管理器,Spring使用PlatfromTransactionManager接口来管理事务,所以需要使用到它的实现类
"transactionManager" class="org.springframework.jdbc.datasource. ">
"dataSource" ref="dataSource">
配置事务管理的模版
"transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
"transactionManager" ref="transactionManager">
在需要进行事务管理的类中,注入事务管理的模版
"accountService" class="my.demo1.AccountServiceImpl">
"accountDao" ref="accountDao">
"transactionTemplate" ref="transactionTemplate">
在业务层使用模版管理事务
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void pay(String out, String in, double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
});
}
声明式事务管理,通过配置文件来完成事务管理(AOP思想)
声明式事务管理分成两种方式
基于AspectJ的xml方式
基于AspectJ的注解方式
基于AspectJ的xml方式
1、恢复转账开发环境
2、引入AOP的开发包
3、配置事务管理器
"transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
"dataSource" ref="dataSource">
4、配置事务增强
"myAdvice" transaction-manager="transactionManager">
"pay" propagation="REQUIRED"/>
5、配置AOP的切面
ref="myAdvice" pointcut="execution(public * my.demo2.AccountServiceImpl.pay(String, String, double))"/>
基于AspectJ的注解方式
1、恢复环境
2、配置事务管理器
"transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
"dataSource" ref="dataSource">
3、开启注解事务
"transactionManager"/>
4、在业务层上添加一个注解@Transactional
5、测试同上
Eclipse的设置(spring的提示换版本或者在eclipsemarket ->popular-> sts)
1、统一工作空间编码 选择utf-8
2、把创建JSP页面的编码修改UTF-8 设置字体大小14
3、重新配置Tomcat服务器
选择服务器-->open-->选择发布该项目的目录(webapps目录)
4、SSH配置约束
<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">
<aop:aspectj-autoproxy />
<bean id="customerDao" class="my.demo1.CustomerDaoImpl"/>
<bean id="myAspectAnno" class="my.demo1.MyAspectAnno"/>
beans>
-- 内置先配置连接池
id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://localhost:3306/spring_day03">property>
<property name="username" value="root">property>
<property name="password" value="123">property>
-- 配置DBCP的连接池 -->
--
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://localhost:3306/spring_day03">property>
<property name="username" value="root">property>
<property name="password" value="123">property>
-- 配置C3P0的连接池 -->
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/spring_day03">property>
<property name="user" value="root">property>
<property name="password" value="123">property>
-- 配置JDBC模版类 -->
id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
<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/spring_day03">property>
<property name="user" value="root">property>
<property name="password" value="123">property>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager">property>
bean>
<bean id="accountService" class="my.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao">property>
<property name="transactionTemplate" ref="transactionTemplate">property>
bean>
<bean id="accountDao" class="my.demo1.AccountDaoImpl">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="pay" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:advisor advice-ref="myAdvice" pointcut="execution(public * my.demo2.AccountServiceImpl.pay(String, String, double))"/>
<aop:aspect>aop:aspect>
aop:config>
<tx:annotation-driven transaction-manager="transactionManager"/>
@Aspect
public class MyAspectAnno {
/**
* 通知类型:@Before前置通知(切入点的表达式)
*/
@Before(value="MyAspectAnno.fun()")
public void log() {
System.out.println("记录");
}
/**
* 最终通知:方法执行成功或者有异常,都会执行
*/
@After(value="execution(public * my.demo1.CustomerDaoImpl.save())")
public void after() {
System.out.println("最终通知");
}
@Around(value="MyAspectAnno.fun()")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知1");
try {
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知2");
}
/**
* 自己定义切入点
*/
@Pointcut(value="execution(public * my.demo1.CustomerDaoImpl.save())")
public void fun() {}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
@Resource(name="customerDao")
private CustomerDao customerDao;
@Test
public void run1() {
customerDao.save();
customerDao.update();
}
}
public class Demo1 {
/**
* 演示模版类
*/
@Test
public void run1() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day03");
dataSource.setUsername("root");
dataSource.setPassword("123");
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource);
template.update("insert into t_account values (null,?,?)","ww",123);
template.update("insert into t_account values (null,?,?)","我的",123);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void run1() {
jdbcTemplate.update("insert into t_account values (null,?,?)","你的12",123);
}
/**
* update(String sql,Object...params)可以完成增删改
*/
@Test
public void run2() {
jdbcTemplate.update("update t_account set name=? where id=?","我得天天",1);
}
/**
* 删除
*/
@Test
public void run3() {
jdbcTemplate.update("delete from t_account where id=?",1);
}
/**
* 查询,通过主键查询一条记录
*/
@Test
public void run4() {
Account ac = jdbcTemplate.queryForObject("select * from t_account where id=?", new BeanMapper(),2);
System.out.println(ac);
}
/**
* 查询所有的数据
*/
@Test
public void run5() {
List list = jdbcTemplate.query("select * from t_account",new BeanMapper());
System.out.println(list);
}
}
/**
* 手动封装数据(一行一行封装数据)
* @author Administrator
*
*/
class BeanMapper implements RowMapper{
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account ac = new Account();
ac.setId(rs.getInt("id"));
ac.setName(rs.getString("name"));
ac.setMoney(rs.getDouble("money"));
return ac;
}
}