动态代理回顾

目录

首先回顾一下代理

静态代理

测试 

动态代理

JDK动态代理

实现步骤(思路)

实现步骤(代码)

补充 


 

首先回顾一下代理

 

简而言之,就是隐藏自己的身份干自己想干的事

对于正向代理

比如说你去访问美国的网站,但是靠你个人是访问不到的(因为不支持国内用户)。所以你得利用中介(也就是代理服务器),对于美国网站来说,他不知道是你还是代理服务器访问的,所以就ok;了;

好处:隐藏了客户端的IP,保证了用户的安全

对于反向代理:

比如说,你是农村种水果的,你要卖水果,但是你在农村不好卖出去,所以你需要通过中介,来进行出售,对于买水果的我们来说,我们是不知道这个水果的来源的,这就是反向代理;

好处:保护了服务器的安全,让用户不知道服务器的ip地址

还涉及了负载均衡,当用户的请求较大时,可以利用负载均衡,设计多个服务器进行处理;

两者区分:

再回到代理

比如说a要调用c的方法,c不给a来访问,所以我们可以利用代理,创建一个b代理,c让b访问,c访问b来访问c;

根据我们实际情况:

比如说我们发短信,肯定是不能直接发短信的,用的是电信移动的子公司或者关联公司,它们有发短信的功能;

代理模式:

 代理模式:

学过设计模式的都知道,因为代理是代理的需求,所以说他需要实现被代理类的方法,当然,代理类可以增加额外的功能;

控制访问:

代理类不让被代理类访问目标对象:例如商家不让用户访问厂家;

静态代理

厂家和商家都需要实现接口方法;

而用户是通过商家来买U盘;

测试 

接口:

package 代理模式.静态代理;

/**
 * @author diao 2022/3/27
 */
public interface UsbSell {
  //返回U盘价格,amount表示一次购买的数量
   float sell(int amount);


}

工厂:

package 代理模式.静态代理.厂家;

import 代理模式.静态代理.UsbSell;

/**
 * @author diao 2022/3/27
 */
//目标类:金士顿厂家,不接受用户单独购买
public class UsbFactory implements UsbSell {

    /**
     * 厂家实现卖U盘的方法
     * @param amount:U盘数量
     * @return
     */
    @Override
    public float sell(int amount) {
        //一个U盘是85元
        return 85.0f;
    }
}

代理类:商家

作用:调用厂家(目标类)的方法 ,完成方法增强,为了面向用户

package 代理模式.静态代理.商家;

import 代理模式.静态代理.UsbSell;
import 代理模式.静态代理.厂家.UsbFactory;

/**
 * @author diao 2022/3/27
 */
//淘宝是一个商家,代理金士顿厂家U盘销售
public class TaoBao implements UsbSell {

    //需要声明商家代理的厂家是谁,这里体现出多态(里氏替换原则)
    private UsbSell factory=new UsbFactory();

    //实现销售U盘
    @Override
    public float sell(int amount) {
        //1.先向厂家发送订单
        float price = factory.sell(amount);

        //2.商家对用户出售,价格得加,因为是代理类
        price+=price;//属于增强功能,代理类在完成目标类方法调用后增强了功能

        System.out.println("淘宝商家返回给一个优惠券");

       //3.增强后的结果
        return price;
    }
}

用户也就是测试类

package 代理模式.静态代理;

import 代理模式.静态代理.商家.TaoBao;

/**
 * @author diao 2022/3/27
 */
public class ShopMain {
    public static void main(String[] args) {
        //1.创建代理的商家,也就是taobao对象
        TaoBao taoBao = new TaoBao();

        float price = taoBao.sell(1);
        System.out.println("用户通过淘宝商家购买U盘单价"+price);
    }
}

当然我们也可以一个代理类(商家)可以代理多个厂家的商品面向用户

错了,不能说代理多个商家,因为你一个代理类,也实现了卖U盘这个接口,但是这个接口中只能出售一种厂家的U盘

但是你可以自定义一些方法,走私其他厂家的U盘;

 代理类:

package 代理模式.静态代理.商家;

import 代理模式.静态代理.UsbSell;
import 代理模式.静态代理.厂家.UsbFactory;
import 代理模式.静态代理.厂家.ZaPaiZi;

/**
 * @author diao 2022/3/27
 */
//代理类weishang
public class WeiShang implements UsbSell {
    //代理的是金士顿和杂牌子,目标类也就是厂家类
    private UsbSell factory=new UsbFactory();
    private UsbSell factory2=new ZaPaiZi();

    @Override
    public float sell(int amount) {
        //1.调用目标类方法
        float price = factory2.sell(amount);

        //2.微商增强目标类的方法
        price+=1;
        return price;


    }

    //3.这里再出售另外一种Upan
    public float sell2(int amount){
        float price = factory.sell(1);
        price+=5;
        return price;
    }
}

用户测试类

package 代理模式.静态代理;

import 代理模式.静态代理.商家.TaoBao;
import 代理模式.静态代理.商家.WeiShang;

/**
 * @author diao 2022/3/27
 */
public class ShopMain {
    public static void main(String[] args) {
        //1.创建代理的商家,也就是taobao对象
        TaoBao taoBao = new TaoBao();

        float price = taoBao.sell(1);
        System.out.println("用户通过淘宝商家购买U盘单价"+price);

        System.out.println("------------------------");

        WeiShang weiShang = new WeiShang();
        float price2 = weiShang.sell(1);
        System.out.println("微商出售的杂牌子U盘价格为:"+price2);

        float price3 = weiShang.sell2(1);
        System.out.println("微商出售的金士顿U盘价格为:"+price3);
    }
}

缺点:

1、当目标类(厂家)增加了,代理类可能会成倍的增加,因为正常来说,一个代理类只能代理一个厂家;

2、耦合太高,当接口增加 一个方法时,目标类,代理类都会需要更改;

但是你可以采用适配器模式,增加一个新的接口对于新的方法和对应的实现类,然后再在厂家中增加实现类对象从而增加方法;

(9条消息) 代理模式-装饰器模式-适配器模式_Fairy要carry的博客-CSDN博客


动态代理

 

目标类(厂家)很多,但是代理类可以很少,当你修改接口方法时,不会影响代理类

代理=增强代码+目标对象 

 作用:是一种创建Java对象的能力,让你不用创建代理类,直接能够创建代理类对象;

之前创建对象:

1.创建类文件,编译为class文件 2.使用构造方法创建类对象

什么是动态代理:

使用JDK反射机制,创建对象能力,创建的是代理类的对象,不用Java文件了;

mybatis就是就是利用动态代理实现了与之绑定的接口的实现类;

所以说为什么我们在业务层中能够实例化接口的对象,实际上这个接口是已经被Mybatis利用动态代理技术实现了的;

个人认为:一切皆递归,一切皆封装,这里的代理也是,无非是递到目标类(厂家),然后返回,归值,直至返回到用户展现的效果;

区别:

静态代理的目标对象是确定的,容易理解,使用方便,目标类过多,代理类会很多;

动态代理的话,目标对象是不确定的,可以给不同的目标类随时创建代理(利用反射),在运行时生成代理类,方便维护;

总结:我们不写代理类,直接利用代理Class对象,根据他创建实例;

JDK动态代理

介绍:动态代理事先是不知道要代理什么,只有在运行时才确定,并且JDK代理只能代理接口;

使用java反射包中的类和接口实现动态代理的功能;

InvocationHandler,Method,Proxy;

JDK动态代理中必须要有接口

 代理类中的这些核心增强方法就放到invoke中进行执行;

java.lang.reflect反射包下,有三个类:InvocationHandler,Method,Proxy。

InvocationHandler:(调用处理器):核心就一个invoke()——>表示代理要干什么

invoke():表示代理对象要执行的功能代码,你的代理类要完成的功能就写到invoke中;

而代理类要完成的功能:

1.调用目标类的目标方法

2.功能增强,在目标方法调用时,增强功能;

package 动态代理;

import 动态代理.impl.HelloServiceImpl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author diao 2022/3/27
 */

/**
 * 区分:非反射是通过new对象然后通过这个对象进行调用方法
 * 而反射就是通过,得到这个对象的method类对象,根据这个method进行invoke得到值
 */
public class Test {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//        HelloService service=new HelloServiceImpl();
//        service.sayHello("张三");

        //通过反射机制执行sayHello方法
        HelloService target=new HelloServiceImpl();

        //获取sayHello名称对应的Method类对象
        Method method = HelloService.class.getMethod("sayHello", String.class);
        System.out.println(method);

        //invoke是Object类,他是Method中的一个方法
        //执行target对象的sayHello,为什么是sayHello?,因为method表示的是sayHello这个方法
        Object res = method.invoke(target, "李四");
    }
}

 target对应proxy代理对象 ; “李四”对应方法参数 ;method就代表Method method;

Method我们是通过JDK中的API通过代理类—>字节码文件调用getMethod()方法获得的

 代理类中的这些核心增强方法就放到invoke中进行执行;

Method类:表示目标类中的方法

Method.invoke()表示执行目标里的方法;

Proxy类:创建代理对象(也激素是我们要的Class对象),之前创建对象都是new类的构造方法,我们使用Proxy类的方法代替new的使用;

newProxyInstance():创建代理对象,代替new

参数:

1.ClassLoader loader 类加载器,负责向内存中加载对象的:a.getClass().getClassLoader()——>用来指名代理对象使用那个类加载器;

2.Class<?>interfaces:接口,用来指名生成哪个对象的代理对象;用接口指定

3.InvocationHandler h:代理类要完成的功能

个人认为,其实反射很简单就是利用类对象获取我们要的东西,为什么要通过类对象呢?

因为他有instanceKlass的指针,可以从内存中调取Class信息,而Class信息是通过类加载器加载字节码文件产生的,这段时期是运行时;

实现步骤(思路)

实现步骤(代码)

 接口

package 代理模式.动态代理;

/**
 * @author diao 2022/3/28
 */
//定义目标接口
public interface USB {

    float sell(int amount);
    String get(String name);
}

目标类

package 代理模式.动态代理.factory;

import 代理模式.动态代理.USB;

/**
 * @author diao 2022/3/28
 */
public class USBFactory implements USB {
    @Override
    public float sell(int amount) {
        System.out.println("目标类中,执行sell方法");
        return 85.0f;
    }

    @Override
    public String get(String name) {
        return "Offer";
    }
}

代理方法的实现(实现InvocationHandler)

package 代理模式.动态代理.factory.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author diao 2022/3/28
 */
public class MySellHander implements InvocationHandler {
    //1.目标对象
    private Object target=null;

    public MySellHander(Object target) {
        this.target = target;
    }

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

        /**target:目标对象,args参数
         * 执行目标方法
         */
        Object res = method.invoke(target, args);

        //进行代理中的增强方法操作
        if(res!=null){
            Float price= (Float) res;
            price+=25;
            res=price;
        }
        return res;
    }
}

 测试(通过newProxyInstance创建代理对象(需要代理目标的装载器,代理对象挂载的接口(与目标类实现一致)),代理方法,代理对象执行的代理方法));

package 代理模式.动态代理;

import 代理模式.动态代理.factory.USBFactory;
import 代理模式.动态代理.factory.handler.MySellHander;

import java.lang.reflect.Proxy;

/**
 * @author diao 2022/3/28
 */
public class MainShop {
    public static void main(String[] args) {
        //1.先创建目标对象
        USBFactory factory = new USBFactory();
        //2.然后创建InvocationHandler对象
        MySellHander handler = new MySellHander(factory);
        //3.创建代理对象,handler表示要完成的功能
        USB proxy = (USB) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),
                handler);

        //proxy:com.sun.proxy.$Proxy0是proxy的类型
        System.out.println("proxy:"+proxy.getClass().getName());
        //4.通过代理执行代理方法,因为proxy此时是一个代理对象,不会执行USBFactory中的sell方法了
        float price = proxy.sell(1);
        System.out.println("动态代理"+price);

    }
}

补充 

在AOP中,我们不是进行切面编程扩展了方法嘛,其实用的也是动态代理,在不改变原有方法(目标类)的基础上,通过动态代理——>实现InvocationHandler以此增强方法,然后通过Proxy对象进行调用; 

cglib动态代理

在mybatis和Spring中使用的,所以说 目标类的方法与类声明不能有final关键字,不然它的子类怎么能够重写他父类的方法进而实现功能修改呢?

那么问题来了,为什么cglib要用目标类的子类呢?

因为子类对象你可以理解为代理对象,他是被增强过了的,所以说我们要求目标类必须是可继承状态;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
错题回顾功能测试用例的设计可以遵循以下步骤和方法: 1. 需求分析:首先,需要从需求文档中明确错题回顾功能的具体要求和功能。这包括用户可以查看错题的方式、展示形式、错题的分类和筛选功能等。 2. 测试计划:根据需求分析的结果,制定测试计划。明确测试的目标、范围和内容,并确定测试的开始和结束日期。 3. 测试设计:根据需求和测试计划,设计错题回顾功能的测试用例。测试用例应包括输入数据、预期结果和执行步骤。例如,可以设计测试用例来验证用户在查看错题时是否能够正确显示错题内容、错题的答案和解析等。 4. 系统测试:在系统测试阶段,执行设计好的测试用例来验证错题回顾功能是否按照需求正常工作。通过输入不同的测试数据,观察系统的反应和输出结果,与预期结果进行比较。 5. 回归测试:在软件的后续版本中,当对错题回顾功能进行修改或添加新功能时,需要进行回归测试,以确保修改后的功能不会对原有的功能产生不良影响。可以使用之前设计的测试用例进行回归测试。 在测试过程中,可以借鉴黑盒测试的优点,如不需要了解内部实现细节、能够测试整个系统等。同时,也要注意黑盒测试的缺点,如无法全面覆盖所有可能的情况、难以检测到代码错误等。 此外,还可以参考软件开发中的探索性测试和可用性测试的方法。探索性测试可以帮助发现系统中的潜在问题和不符合预期的行为。可用性测试可以评估错题回顾功能的易学性、易记性、容错性、交互效率和用户满意度等指标。 总结起来,设计错题回顾功能测试用例需要进行需求分析、测试计划制定、测试设计、系统测试和回归测试等步骤,并可以借鉴黑盒测试、探索性测试和可用性测试的方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [秋招笔试错题整理](https://blog.csdn.net/qq_43767234/article/details/121457239)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [敏捷ACP.知识总结.错题回顾](https://blog.csdn.net/u010025781/article/details/125473903)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fairy要carry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值