SpringAOP

面向切面编程是指通过预编译和运行期动态代理的方式实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
代理模式
代理模式作为23种经典设计模式之一,其比较官方的定义为“为其他对象提供一种代理以控制对这个对象的访问”,简单点说就是,之前A类自己做一件事,在使用代理之后,A类不直接去做,而是由A类的代理类B来去做。代理类其实是在之前类的基础上做了一层封装。java中有静态代理、JDK动态代理、CGLib动态代理的方式。静态代理指的是代理类是在编译期就存在的,相反动态代理则是在程序运行期动态生成的

静态代理 & 动态代理
1 静态代理
一个接口,两个实现类,代理实现类组合真实实现类

2 动态代理
JDK动态代理和CGlib字节码动态代理

简单转账功能
新建Maven项目名为“spring-aop“

准备数据

删除spring_aop数据库

drop database if exists spring_aop;

创建spring_aop数据库

create database spring_aop;

使用spring_aop数据库

use spring_aop;

创建account表

create table account (
id int(11) auto_increment primary key,
accountNum varchar(20) default NULL,
money int(8) default 0
);

新增数据

insert into account (accountNum, money) values
(“622200001”,1000),(“622200002”,1000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
导包

org.springframework spring-test 5.2.13.RELEASE test commons-dbutils commons-dbutils 1.7 mysql mysql-connector-java 8.0.23 com.mchange c3p0 0.9.5.5 junit junit 4.13.2 test 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 核心配置文件 <?xml version="1.0" encoding="UTF-8"?>

<!-- bean definitions here -->
<context:component-scan base-package="dao"/>
<context:component-scan base-package="services"/>
<context:component-scan base-package="utils"/>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 代码编写

package utils;

@Component
public class ConnectionUtils {
private ThreadLocal tl = new ThreadLocal();
@Autowired
private ComboPooledDataSource dataSource;

/**
 * 获得当前线程绑定的连接
 *
 * @return
 */
public Connection getThreadConnection() {
    try {
        // 看线程是否绑了连接
        Connection conn = tl.get();
        if (conn == null) {
            // 从数据源获取一个连接
            conn = dataSource.getConnection();
            // 和线程局部变量  绑定
            tl.set(conn);
        }
        // 返回线程连接
        return tl.get();
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

/**
 * 把连接和当前线程进行解绑
 */
public void remove() {
    tl.remove();
}

}
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
Account模块实体类:Account.java

package entity;

public class Account {
private Integer id;
private String accountNum;
private Integer money;
// 省略getter&setter方法
}
1
2
3
4
5
6
7
8
Account模块Dao层:AccountDao.java

package dao;

public interface AccountDao {
/**
* 更新
*
* @param account
*/
void updateAccount(Account account);

/**
 * 根据编号查询账户
 *
 * @param accountNum
 * @return 如果没有结果就返回null,如果结果集超过一个就抛异常,如果有唯一的一个结果就返回
 */
Account findAccountByNum(String accountNum);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Account模块Dao层实现类:AccountDaoImpl.java

package dao.impl;

@Repository(“accountDao”)
public class AccountDaoImpl implements AccountDao {
// 数据库查询工具类
@Autowired
private QueryRunner runner;
// 数据库连接工具类
@Autowired
private ConnectionUtils connectionUtils;

/**
 * 更新
 *
 * @param account
 */
public void updateAccount(Account account) {
    try {
        runner.update(connectionUtils.getThreadConnection(),
                "update account set accountNum=?,money=? where id=?",
                account.getAccountNum(), account.getMoney(), account.getId());
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

/**
 * 根据编号查询账户
 *
 * @param accountNum
 * @return 如果没有结果就返回null,如果结果集超过一个就抛异常,如果有唯一的一个结果就返回
 */
public Account findAccountByNum(String accountNum) {
    List<Account> accounts = null;
    try {
        accounts = runner.query(connectionUtils.getThreadConnection(),
                "select * from account where accountNum = ? ",
                new BeanListHandler<Account>(Account.class),
                accountNum);
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
    if (accounts == null || accounts.size() == 0) {
        // 如果没有结果就返回null
        return null;
    } else if (accounts.size() > 1) {
        // 如果结果集超过一个就抛异常
        throw new RuntimeException("结果集不唯一,数据有问题");
    } else {
        // 如果有唯一的一个结果就返回
        return accounts.get(0);
    }
}

}
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
52
53
54
Account模块Service层:AccountService.java

package services;

public interface AccountService {
/**
* 转账
*
* @param sourceAccount 转出账户
* @param targetAccount 转入账户
* @param money 转账金额
*/
void transfer(String sourceAccount, String targetAccount, Integer money);
}
1
2
3
4
5
6
7
8
9
10
11
12
Account模块Service层实现类:AccountServiceImpl.java

package services.impl;

@Service(“accountService”)
public class AccountServiceImpl implements AccountService {

@Autowired
private AccountDao accountDao;

/**
 * 转账
 *
 * @param sourceAccount 转出账户
 * @param targetAccount 转入账户
 * @param money         转账金额
 */
public void transfer(String sourceAccount, String targetAccount, Integer money) {
    // 查询原始账户
    Account source = accountDao.findAccountByNum(sourceAccount);
    // 查询目标账户
    Account target = accountDao.findAccountByNum(targetAccount);
    // 原始账号减钱
    source.setMoney(source.getMoney() - money);
    // 目标账号加钱
    target.setMoney(target.getMoney() + money);
    // 更新原始账号
    accountDao.updateAccount(source);
    // 更新目标账号
    accountDao.updateAccount(target);
    System.out.println("转账完毕");
}

}
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
Account模块测试类:AccountTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = “classpath:applicationContext.xml”)
public class AccountTest {

@Autowired
private AccountService accountService;

@Test
public void testTransfer() {
    accountService.transfer("622200001", "622200002", 100);
}

}
1
2
3
4
5
6
7
8
9
10
11
12

引入AOP(XML)
代码实现

删除事务代理工具类:TransactionProxyUtils.java

导入aspectjweaver包

org.aspectj aspectjweaver 1.9.3 1 2 3 4 5 6 配置文件中添加 AOP 的相关配置

aop:config

<aop:pointcut expression=“execution ( * services..(…))” id=“pc”/>

<aop:aspect ref=“transactionManager”>
<aop:before method=“beginTransaction” pointcut-ref=“pc”/>
<aop:after-returning method=“commit” pointcut-ref=“pc”/>
<aop:after method=“release” pointcut-ref=“pc”/>
<aop:after-throwing method=“rollback” pointcut-ref=“pc”/>
</aop:aspect>
</aop:config>
1
2
3
4
5
6
7
8
9
10
11
12
修改测试类代码

XML改注解(AOP)
代码实现

删除XML中的AOPXML配置并注解代理模式

aop:aspectj-autoproxy</aop:aspectj-autoproxy>

1
2
3
注释事务管理器类:TransactionManager.java

package transaction;

@Component
@Aspect
public class TransactionManager {
// 数据库连接工具类
@Autowired
private ConnectionUtils connectionUtils;

@Pointcut("execution(* services.*.*(..))")
private void transactionPointcut() {
}

/**
 * 开启事务
 */
@Before("transactionPointcut()")
public void beginTransaction() {
    try {
        System.out.println("开启事务");
        connectionUtils.getThreadConnection().setAutoCommit(false);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 提交事务
 */
@AfterReturning("transactionPointcut()")
public void commit() {
    try {
        System.out.println("提交事务");
        connectionUtils.getThreadConnection().commit();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 回滚事务
 */
@AfterThrowing("transactionPointcut()")
public void rollback() {
    try {
        System.out.println("回滚事务");
        connectionUtils.getThreadConnection().rollback();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 释放连接
 */
@After("transactionPointcut()")
public void release() {
    try {
        System.out.println("释放连接");
        connectionUtils.getThreadConnection().close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    connectionUtils.removeConnection();
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值