JAVA学习日志3-5(spring 动态代理)

动态代理
代理可以理解为在某个操作前后添加另一些操作,如在进行转账操作前添加开启手动提交事务的操作,在转账操作结束后添加提交事务或回滚事务的操作。如果转账操作记为A操作,添加了事务后的A操作就可以成为A操作的代理。当使用A操作时使用的A操作的代理。事务的操作并不是业务操作,和转账业务是不想关,所以需要将二者进行分离。
需要在transfer内的代码中添加事务相关的代码

  • 静态代理
    在这里插入图片描述
    由于dao层使用connection对象是从链接池中会获取的,每个操作可能不再同一个链接上,所以直接进行事务操作时不合理的。可以定义一个容器来存储connection,时dao和service都使用同一对象。在一个线程中线程对象是不会变的,所有可以使用map来存储范型是<Thread,Connection>。在定义一个connection管理类来负责线程的操作(分发连接,开启事务等)
public class ConnStore {
    private static Map<Thread, Connection> connMap = new HashMap<Thread, Connection>();
    public static void putConn(Connection conn){
        connMap.put(Thread.currentThread(),conn);
    }

    public static Connection getConn(Thread thread){
        return  connMap.get(thread);
    }

    public static void remove(Thread thread){
        connMap.remove(thread);
    }
}
public class ConnManage {

    public static Connection getConn(){
        Connection conn = null;
        try {
            if(ConnStore.getConn(Thread.currentThread())==null){
                DataSource ds = new ComboPooledDataSource("c3p0-config.xml");
                conn = ds.getConnection();
                ConnStore.putConn(conn);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return ConnStore.getConn(Thread.currentThread());
    }
    
    public static void setAutoCommit(){
        Connection conn = getConn();
        try {
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static  void commit(){
        Connection conn = ConnStore.getConn(Thread.currentThread());
        try {
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public  static void callback(){
        Connection conn = ConnStore.getConn(Thread.currentThread());
        try {
            conn.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}
public class UserDaoImpl implements UserDao {

    QueryRunner queryRunner = new QueryRunner();
    public User findUser(String uname) {
        String sqlStr = "select * from user where uname = ?";
        User user = null;
        try {
            user = queryRunner.query(ConnManage.getConn(),sqlStr,new BeanHandler<User>(User.class),uname);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return  user;

    }

    public int updae(User user) {
        String sqlStr = "update user set money = ? where uname = ?";
        Object []objects = {user.getMoney(),user.getUname()};
        int num = -1;
        try {
            num = queryRunner.update(ConnManage.getConn(),sqlStr,objects);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return num;
    }

}
public class UserServiceImpl implements UserService {

    private UserDao userDao = new UserDaoImpl();

    public void transfer(String name1, String name2, int monney) {
        try {
            //找到对象,进行转账
            User user1 = userDao.findUser(name1);
            User user2 = userDao.findUser(name2);
            user1.setMoney(user1.getMoney()-monney);
            user2.setMoney(user2.getMoney()+monney);

            ConnManage.setAutoCommit();
            userDao.updae(user1);
//            int num = 0/0;
            userDao.updae(user2);
            ConnManage.commit();
        } catch (Exception e) {
            ConnManage.callback();
        }
    }
}
  • 动态代理(Proxy)
    在上述操作中dao层的业务代码和事务代码没有进行分离
    使用动态代理来进行分离,程序在运行期间才产生添加了操作类
    代理对象中需要获得被代理的对象,这里通过构造方法传递
public class UserProxy implements InvocationHandler {

    private UserService userService;
    public UserProxy(UserService userService){
        this.userService=userService;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            //添加事务操作
            ConnManage.setAutoCommit();
            //通过反射进行业务操作
            method.invoke(userService,args);
            //提交事务
            ConnManage.commit();
        } catch (Exception e) {
            //回滚事务
            ConnManage.callback();
        }
        return null;
    }
}

service层

public class UserServiceImpl2 implements UserService {

    public UserDao userDao = new UserDaoImpl();

    public void transfer(String name1, String name2, int monney) {
        User user1 = userDao.findUser(name1);
        User user2 = userDao.findUser(name2);
        user1.setMoney(user1.getMoney()-monney);
        user2.setMoney(user2.getMoney()+monney);
        userDao.updae(user1);
        userDao.updae(user2);
    }
}

调用,userService2是userService 的代理对象,添加了事务的操作

    @org.junit.Test
    public void Test2(){
        UserService userService = new UserServiceImpl2();
        UserService userService2 = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),new UserProxy(userService));
        userService2.transfer("a","b",10);
    }
  • 动态代理(cglib)
public class UserCglib implements InvocationHandler {

    private UserService userService;
    public UserCglib(UserService userService){
        this.userService=userService;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        try {
            ConnManage.setAutoCommit();
            method.invoke(userService,args);
            ConnManage.commit();
        } catch (Exception e) {
            ConnManage.callback();
        }
        return null;
    }
}

调用

    @org.junit.Test
    public void Test3(){
        UserService userService = new UserServiceImpl2();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new UserCglib(userService));
        UserService userService1 = (UserService) enhancer.create();
        userService1.transfer("a","b",5);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值