3.Spring学习之路(动态代理)

1.什么是动态代理:
我的理解就是首先它是动态的,即随用随创建,随用随加载,其次在不修改源码的基础上对原有的方法进行增强。比如我们写了一个类,然后需要在里面写上打印日志,判断执行效率这些常用的方法,如果我们每一个都写的话,就很臃肿,这时候动态代理可以帮我们做这样的事情。
2.动态代理的分类:
基于接口的动态代理
基于子类的动态代理
二者的区别是什么,各自实现什么样的功能呢?
(1).首先涉及到Proxy(代理)类,然后通过Proxy的newProxyInstance来创建代理对象,同时,被代理的类至少实现一个接口,否则的话不能使用,然后上面newProxyInstance方法中的三个参数
ClassLoader(类加载器):固定的写法,被代理的类.getClass().getClassLoader(),
Class[](字节码数组):固定的写法,被代理的类.getClasss().getInterfaces()
InvocationHandler(用于提供增强的方法):然后这个参数就是最难写的,它是让我们如何去代理的,一般都是一个接口的实现类,通常情况都是匿名内部类,此接口的实现类都是谁用谁写。

            new InvocationHandler() { 
            /**
                 * 作用:执行被代理对象的任何接口方法都会经过该方法
                 * 方法参数的含义
                 * @param proxy   代理对象的引用
                 * @param method  当前执行的方法
                 * @param args    当前执行方法所需的参数
                 * @return        和被代理对象方法有相同的返回值
                 * @throws Throwable
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //提供增强的代码
                    Object returnValue = null;

                    //1.获取方法执行的参数
                    Float money = (Float)args[0];
                    //2.判断当前方法是不是销售
                    if("saleProduct".equals(method.getName())) {
                        returnValue = method.invoke(producer, money*0.8f);
                    }
                    return returnValue;
                }
            });

(2).基于子类的动态代理,涉及到的类是Enhancer,是cglib提供的,然后它代理的类不能是最终类,即final修饰的类,通过create来创建代理对象,然后create里面只有两个参数
Class(字节码):固定的写法,被代理类.getClass()
Callback(用于增强的代码):这个和上面的第三个参数一样是最难的,一个该接口的实现类,是为了让我们写出如何代理的,通常情况都是匿名内部类,此接口的实现类谁用是写。

Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {

    /**
     * 执行cglib创建对象的任何方法都会经过该方法
     * @param proxy
     * @param method
     * @param args
     *    以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
     * @param methodProxy :当前执行方法的代理对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //提供增强的代码
        Object returnValue = null;

        //1.获取方法执行的参数
        Float money = (Float)args[0];
        //2.判断当前方法是不是销售
        if("saleProduct".equals(method.getName())) {
            returnValue = method.invoke(producer, money*0.8f);
        }
        return returnValue;
    }
});

3.动态代理应用的两个例子:
然后写了两个demo,大致的样式如下图所示
在这里插入图片描述

package com.itheima.cglib;

import com.itheima.proxy.IProducer;

public class Producer implements  IProducer{
    public void saleProduct(float money){
        System.out.println("拿到钱,销售产品,并销售产品"+money);

    }
    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱"+money);
    }
}

public class client {
    public static void main(String[] args) {
        final Producer producer=new Producer();
       Producer cglibProducer=(Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {

            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object returnvalue=null;
                Float money=(Float)objects[0];
                if("saleProduct".equals(method.getName())){
                    returnvalue= method.invoke(producer,money*0.8f);
                }
                return returnvalue;
            }
        });
        cglibProducer.saleProduct(1000f);
    }
}

–下面对应的是下面三个类---------------------------------------------------------------------

public interface IProducer {
    public  void saleProduct(float money);
    public void afterService(float money);
}
public class Producer implements  IProducer{
    public void saleProduct(float money){
        System.out.println("拿到钱,销售产品,并销售产品"+money);

    }
    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱"+money);
    }
}
public class client {
    public static void main(String[] args) {
        final   Producer producer=new Producer();
      IProducer proxyProducer=(IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
//            执行被代理对象的任何接口方法都会经过该方法
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                        提供增强的代码
                        Object returnvalue=null;
                        Float money=(Float)args[0];
                        if("saleProduct".equals(method.getName())){
                            returnvalue= method.invoke(producer,money*0.8);
                        }
                        return returnvalue;

                    }
                }
        );
      proxyProducer.saleProduct(1000f);
    }
}

动态代理的另外一个例子
银行转账的时候,需要完成这几个步骤
//1根据名称查询转出账户
Account source = accountDao.findAccountByName(sourceName);
//2根据名称查询转入账户
Account target = accountDao.findAccountByName(targetName);
//3转出账户减钱
source.setMoney(source.getMoney()-money);
//4转入账户加钱
target.setMoney(target.getMoney()+money);
//5更新转出账户
accountDao.updateAccount(source);
//6更新转入账户
accountDao.updateAccount(target);
但是如果在第5步之后出现了异常,这时候如果没有事务回滚,那么转出账户钱减少了,但是转入账户的钱并没有增加,这时候我们可以加上一个事务

  try {
            //1.开启事务
            txManager.beginTransaction();
            //2.执行操作

            //2.1根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);
            //2.2根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);
            //2.3转出账户减钱
            source.setMoney(source.getMoney()-money);
            //2.4转入账户加钱
            target.setMoney(target.getMoney()+money);
            //2.5更新转出账户
            accountDao.updateAccount(source);

            int i=1/0;

            //2.6更新转入账户
            accountDao.updateAccount(target);
            //3.提交事务
            txManager.commit();

        }catch (Exception e){
            //4.回滚操作
            txManager.rollback();
            e.printStackTrace();
        }finally {
            //5.释放连接
            txManager.release();
        }

这个属于一个转账的功能,如果我们删除账户,查询账户等等都可能遇到异常,都需要加上事务管理这个功能,那么我们可以创建一个工厂类:获取代理对象

 public IAccountService getAccountService() {
        return (IAccountService)Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 添加事务的支持
                     *
                     * @param proxy
                     * @param method
                     * @param args
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        if("test".equals(method.getName())){
                            return method.invoke(accountService,args);
                        }
                        Object rtValue = null;
                        try {
                            //1.开启事务
                            txManager.beginTransaction();
                            //2.执行操作
                            rtValue = method.invoke(accountService, args);
                            //3.提交事务
                            txManager.commit();
                            //4.返回结果
                            return rtValue;
                        } catch (Exception e) {
                            //5.回滚操作
                            txManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            //6.释放连接
                            txManager.release();
                        }
                    }
                });

    }

然后配置代理的service,然后测试代理的service可以发现每一个测试类都会实现增强的代理方法
在这里插入图片描述

public class AccountServiceTest {

    @Autowired
    @Qualifier("proxyAccountService")
    private  IAccountService as;
     @Test
    public void testTransfer(){
         as.transfer("aaa","bbb",100f);

     }

}

这里因为我在配置的时候,原始的配置service我还保留了,所以如果不加上==@Qualifier==那么就会显示有两个service。最后执行一下,可以发现发现,如果转账的时候出现了异常,那么事务管理就会回滚,从而使系统的可靠性得到了提升!

weixin073智慧旅游平台开发微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值