目录
(一)什么是动态代理模式
动态代理是java的一种设计模式。它的特征就是委托类和代理类具有相同的接口,代理类是在委托类的代码基础上添加了其他功能,比如消息预处理、消息过滤和事后处理消息等。但是实际上业务逻辑还是有委托类去完成的,简单来说,调用委托类的时候是通过代理对象来实现的。
代理类是在程序运行的时候 创建的所以被称为动态代理。动态代理相对于静态代理更加灵活,能够根据java代码指示动态生成
(二)动态代理模式入门案例
1.完成一个账户转账的功能
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`usernumber` varchar(255) NOT NULL,
`money` double NOT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(1)创建实体类
(2)创建DAO层
创建接口:
实现类:
public class AccountDaoImpl implements AccountDao {
QueryRunner qr = new QueryRunner();
//获取连接
Connection conn = JDBCUtils.getConnection();
@Override
public Account getAccountByNo(String usernumber) throws SQLException {
return qr.query(conn,"select * from account where usernumber = ?",new BeanHandler<>(Account.class),usernumber);
}
@Override
public int editAccout(Account account) throws SQLException{
return qr.update(conn,"update account set usernumber = ? , password = ? , money = ? where id = ?",
account.getUsernumber(),account.getPassword(),account.getMoney(),account.getId());
}
@Override
public int addAccount(Account account) throws SQLException {
return qr.update(conn,"insert into account (usernumber,password,money) values(?,?,?)",
account.getUsernumber(),account.getPassword(),account.getMoney());
}
@Override
public int delAccount(int id) throws SQLException{
return qr.update(conn,"delete from account where id = ?",id);
}
}
(3)创建业务层
实现类:
public class AccountServiceImpl implements AccountService {
AccountDao accountDao = new AccountDaoImpl();
@Override
public boolean transfer(String userNo1, String userNo2, double money) {
try {
//查询账户一的具体内容
Account accout1 = accountDao.getAccountByNo(userNo1);
//查询账户二的内容
Account account2 = accountDao.getAccountByNo(userNo2);
//对标账户一余额是否够
if(accout1.getMoney() > money){
//转户一转账
accout1.setMoney(accout1.getMoney() - money);
//转户二加钱
account2.setMoney(account2.getMoney() + money);
//转账
accountDao.editAccout(accout1);
accountDao.editAccout(account2);
//完成
return true;
}else {
System.out.println("账户"+accout1.getUsernumber()+"余额不足");
return false;
}
}catch (Exception e){
System.out.println("转账失败");
System.out.println(e.getMessage());
return false;
}
}
}
(4)创建测试类
结果:
如果修改下代码:在业务层手动添加异常
结果:
数据库:
添加事务
2. v1.0版本为转账添加一个事务
修改持久层代码:
修改业务层代码:
在转账的方法中添加事务:
测试:
结果:
数据库:
问题:每次在业务层添加事务都需要我们程序员手动的添加,不太符合业务分层。出现层次混乱问题。
3.v2.0将事务从业务层和从持久层剥离
创建一个事务管理的工具类
public class TxManage {
//获取当前线程进程的容器
public static ThreadLocal<Connection> TL = new ThreadLocal<Connection>();
//获取连接的方法
public static Connection getConn(){
//创建一个连接的变量
Connection conn = TL.get();
//判断该连接是否在线程容器中存在
if(conn == null){
//创建一个连接
conn = JDBCUtils.getConnection();
//将该连接放入到线程容器中
TL.set(conn);
}
//返回连接
return conn;
}
//事务开启的方法
public static void begin(){
try {
getConn().setAutoCommit(false);
}catch (Exception e){
e.printStackTrace();
}
}
//事务提交的方法
public static void commit(){
try {
getConn().commit();
}catch (Exception e){
e.printStackTrace();
}
}
//事务回滚的方法
public static void rollback(){
try {
getConn().rollback();
}catch (Exception e){
e.printStackTrace();
}
}
//关闭连接的方法
public static void close(){
//判断线程容器中连接是否为空
if(TL.get() != null){
try {
TL.get().close();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//删除线程容器中的对象
TL.remove();
}
}
}
}
改造持久层:
修改业务层:
public class AccountServiceImpl implements AccountService {
//手动创建持久层
AccountDao accountDao = new AccountDaoImpl();
@Override
public boolean transfer(String userNo1, String userNo2, double money) {
try {
//打开事务
TxManage.begin();
//查询账户一的具体内容
Account accout1 = accountDao.getAccountByNo(userNo1);
//查询账户二的内容
Account account2 = accountDao.getAccountByNo(userNo2);
//对标账户一余额是否够
if(accout1.getMoney() > money){
//转户一转账
accout1.setMoney(accout1.getMoney() - money);
//转户二加钱
account2.setMoney(account2.getMoney() + money);
//转账
accountDao.editAccout(accout1);
//手动添加错误
int i = 1 / 0 ;
accountDao.editAccout(account2);
//提交事务
TxManage.commit();
//完成
return true;
}else {
System.out.println("账户"+accout1.getUsernumber()+"余额不足");
return false;
}
}catch (Exception e){
System.out.println("转账失败");
System.out.println(e.getMessage());
//回顾事务
TxManage.rollback();
return false;
}
}
测试:
数据库:
代码问题:事务相对的操作在业务层手动实现的,如果我们创建一个别的功能,要添加事务,必须手动添加事务。
4.v3.0将事务使用动态代理完成
将事务在业务逻辑中剥离,使用动态代理创建。
新建一个动态代理实现的类:
//创建的动态代理类
public class DynamicProxy implements InvocationHandler {
//创建一个代表委托类的属性
private Object object;
//创建一个构造方法,要求在创建代理类的时候,将委托类添加进来
public DynamicProxy(Object object) {
this.object = object;
}
//生成代理类的方法
public Object createProxy(){
//生成代理类的方法
Object proxy = Proxy.newProxyInstance(object.getClass().getClassLoader()
,object.getClass().getInterfaces(),this);
//返回代理类
return proxy;
}
//代理类方法执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object o = null;
try {
//开启事务
o = method.invoke(object,args); TxManage.begin();
//执行委托类原来的方法
//提交事务
TxManage.commit();
}catch (Exception e){
//回滚事务
TxManage.rollback();
}finally {
//关闭连接
TxManage.close();
}
return o;
}
}
修改持久层代码:
接口中异常处理去掉:
修改业务层:
public class AccountServiceImpl implements AccountService {
//手动创建持久层
AccountDao accountDao = new AccountDaoImpl();
@Override
public boolean transfer(String userNo1, String userNo2, double money) {
//查询账户一的具体内容
Account accout1 = accountDao.getAccountByNo(userNo1);
//查询账户二的内容
Account account2 = accountDao.getAccountByNo(userNo2);
//对标账户一余额是否够
if (accout1.getMoney() > money) {
//转户一转账
accout1.setMoney(accout1.getMoney() - money);
//转户二加钱
account2.setMoney(account2.getMoney() + money);
//转账
accountDao.editAccout(accout1);
//手动添加错误
int i = 1 / 0;
accountDao.editAccout(account2);
//完成
return true;
}else{
return false;
}
}
测试:
结果:
如果在转账过程中添加异常:
结果:
动态代理的特点:
是java自带的功能,使用动态代理的时候必须有接口
如果没有接口,还需要使用代理,怎样处理?
5.v3.0通过cglib实现代理模式
cglib是通过继承来实现代理
- 导入cglib依赖
2.创建cglib代理类
public class CglibProxy implements MethodInterceptor {
//创建一个委托对象的属性
private Object object;
//创建构造方法 在创建代理类的时候要委托类
public CglibProxy(Object object) {
this.object = object;
}
//创建一个构造方法 创建类的时候将委托类放入
public Object createProxy(){
//创建cglib的主类
Enhancer ec = new Enhancer();
//添加父类,父类就是委托类
ec.setSuperclass(object.getClass());
//设置cglib代理对象的类
ec.setCallback(this);
//创建代理对象并返回
return ec.create();
}
//cglib代理执行的方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//创建返回值
Object obj = false;
try {
//开启事务
TxManage.begin();
//调用委托类的方法
obj = methodProxy.invokeSuper(o,objects);
//提交事务
TxManage.commit();
}catch (Exception e){
//回顾事务
TxManage.rollback();
}finally {
TxManage.close();
}
return obj;
}
}
创建一个新的业务层:不使用接口创建,里面写转账的方法:
测试:
动态代理不能代理没有接口的类:
更改cglib代理:
测试:
cglib是通过继承来实现的代理