目录
(一)什么是动态代理模式
(二)动态代理模式入门案例
1.完成一个账户转账的功能
2. v1.0版本为转账添加一个事务
3.v2.0将事务从业务层和从持久层剥离
4.v3.0将事务使用动态代理完成
5.v3.0通过cglib实现代理模式
(一)什么是动态代理模式
动态代理是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();@Overridepublic Account getAccountByNo(String usernumber) throws SQLException {return qr.query(conn,"select * from account where usernumber = ?",new BeanHandler<>(Account.class),usernumber);}@Overridepublic 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());}@Overridepublic int addAccount(Account account) throws SQLException {return qr.update(conn,"insert into account (usernumber,password,money) values(?,?,?)",account.getUsernumber(),account.getPassword(),account.getMoney());}@Overridepublic 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();@Overridepublic 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();@Overridepublic 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;}//代理类方法执行@Overridepublic 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();@Overridepublic 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代理执行的方法@Overridepublic 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是通过继承来实现的代理