首页 > 编程语言 >JAVA代理-----详细深入介绍

JAVA代理-----详细深入介绍

时间:2024-09-08 19:52:36浏览次数:14  
标签:JAVA 对象 代理 DTXSD ----- new 方法 public

什么是代理(定义)

定义:给目标对象提供一个代理对象,并且由代理对象控制对目标对象的引用

为什么要使用JAVA代理(目的)

1.功能增强:通过代理业务对原有业务进行增强

2.控制访问通过代理对象的方式间接的范文目标对象,防止直接访问目标对象给系统带来不必要的复杂性。

例:银行转账的系统的三个功能

1.判断用户的身份,做用户验证,判断用户金额

2.转账的方法

3.事后服务

如果在一个方法中写入这三件事

这会使方法的功能量太大

如何降低功能量?

1.将这一个方法转换成三个方法

这会使功能比较灵活,效率比较高,但是没有考虑扩容的问题

2.支付宝代理转账业务

如果本身是一个银行,需要向支付宝公司提供转账方法

我们可以把验证和事后服务这两个业务交给支付宝公司,银行只需要控制转账方法。

代理模式

代理模式:最核心的业务也就是转账的业务自己做,由支付宝公司代理,用户不能直接进行转账服务这种最核心业务,需要通过支付宝进行转账代理

支付宝公司对银行的转账业务进行代理,用户只能去访问支付宝,再由支付宝进行身份核验之后,去调用当前的转账方法。

代理模式的好处

1.防止用户直接访问核心方法,带来一些不必要的危机

用户直接访问转账服务,就可能造成金融上的问题

2.能够对核心方法进行功能的增强

java代理怎么用?

java代理

1.静态代理

也称为 基于JDK实现的静态代理

静态代理的模式

核心类(目标类)生成核心对象(目标对象),同时由代理类实现代理对象,再由代理对象代理核心对象

核心类和代理类都会实现接口

接口起到的作用就是通知当前代理类所要代理的核心类的核心功能

 静态代理流程图

例:支付宝代理银行转账的静态代理
银行类----->核心类
package work0903;

public class YinHang implements ZhanZhang{
    @Override
    public void zhuanzhang(String A, String B, Double money) {
        System.out.println(A+"给"+B+"转账了"+money);
    }
}
支付宝类------>代理类
package work0903;

public class ZhiFuBao implements ZhanZhang{
    //定义被代理的类---------->核心类
    private YinHang yinHang=new YinHang();
    private void yanzheng(String A, String B, Double money){
        System.out.println("对A进行了身份验证");
        System.out.println("对B进行了身份验证");
        System.out.println("对转账金额进行了验证");
    }
    @Override
    public void zhuanzhang(String A, String B, Double money) {
        yanzheng(A,B,money);
        yinHang.zhuanzhang(A,B,money);
        fuwu();//功能增强
    }
    private void fuwu(){
        System.out.println("转账完成后进行服务");
    }
}
接口
package work0903;

public interface ZhanZhang {
    //定义核心方法
    public void zhuanzhang(String A,String B,Double money);
}
测试类
package work0903;

public class Test {
    public static void main(String[] args) {
        ZhiFuBao zhiFuBao=new ZhiFuBao();
        zhiFuBao.zhuanzhang("张三","李四",100.0);
    }
}
执行结果

执行流程

1.首先Test类的main方法入栈

2.创建zhifubao对象(代理对象)

3.zhifubao对象会创建yinhang对象(核心对象)

3.zhifubao对象中有yanzhen方法和fuwu方法,以及zhuanzhang方法

4.yinhang对象中也有自身的zhuanzhang方法(核心方法)

5.调用zhifubao中的zhuanzhang方法,该方法入栈

6.zhifubao中的zhuanzhang方法会继续调用yinhang的zhuangzhang方法

7.同时也会调用自身的yanzheng方法和fuwu方法,进行了业务增强

程序执行内存图

代理类和核心类的关系:

代理对象代理核心对象,核心对象在代理对象的内部

对于用户来说:用户调用代理对象,代理对象再调用核心对象,这样就防止了用户直接访问到当前核心对象所带来一些麻烦,同时的话还能对核心方法进行一系列的增强

示例:销售店代理衣服工厂
接口
package DaiLi;

public interface Clothes {

    public void BuyClothes(String size);

}

核心类
package DaiLi;

public class ClothesFactory implements Clothes {
    @Override
    public void BuyClothes(String size) {
        System.out.println("定制一件大小为"+size+"的衣服");
    }
}
代理类
package DaiLi;

public class XSD implements Clothes{
    //1.代理目标类
    private ClothesFactory clothesFactory=new ClothesFactory();

    private void fuwu(){
        System.out.println("销售店的售后服务");
    }

    @Override
    public void BuyClothes(String size) {
        clothesFactory.BuyClothes(size);
        fuwu();
    }
}
测试类
package DaiLi;

public class Test {
    public static void main(String[] args) {

       XSD xsd=new XSD();
       xsd.BuyClothes("XXL");
    }

}
执行结果

静态代理的缺陷:

用一个代理类代理多个目标类是很难实现的,会出现问题

例:销售店不仅代理衣服工厂,还代理鞋子工厂,
鞋子接口
package DaiLi;

public interface Shoes {
    public void BuyShoes(String size);

}
核心类
package DaiLi;

public class ShoeFactory implements Shoes{
    @Override
    public void BuyShoes(String size) {
        System.out.println("定制一款大小为"+size+"的鞋子");
    }
}
代理类
package DaiLi;

public class XSD implements Clothes,Shoes{
    //1.代理目标类
    private ClothesFactory clothesFactory=new ClothesFactory();
    private ShoeFactory shoeFactory=new ShoeFactory();
    private void fuwu(){
        System.out.println("销售店的售后服务");
    }

    @Override
    public void BuyClothes(String size) {
        clothesFactory.BuyClothes(size);
        fuwu();
    }

    @Override
    public void BuyShoes(String size) {
        shoeFactory.BuyShoes(size);
        fuwu();
    }
}
测试类
package DaiLi;

public class Test {
    public static void main(String[] args) {

       XSD xsd=new XSD();
       xsd.BuyClothes("XXL");
       xsd.BuyShoes("39");
    }

}

静态代理的模式图

每一个代理对象当中代理的目标类太多了,主要是因为在每个代理对象当中都会创建全部的目标对象。

2.动态代理

动态代理的分类

1.基于JDK实现的动态代理

2.基于CGLB实现的动态代理

动态代理定义:

所谓动态代理,就是当前的代理类去动态的生成代理对象,匹配每个目标对象。

代理类实现代理对象,一个类可以实现多个对象,每个代理对象代理一个目标对象,只包含自己要代理的目标对象

动态代理模式图

代理类会生成代理对象,专门代理目标类

动态代理的实现
1.动态代理一对一模式的形成

代理类会指定自己要代理的目标类对象

package DaiLi;

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

public class DTXSD {
    private Object object;  //目标类
    public DTXSD(Object o) {
        object = o;
    }

    
}
package DaiLi;

public class Test {
    public static void main(String[] args) {

       //实现一个动态代理对象代理一个目标对象的方法
        //方法1
        // DTXSD dtxsd1=new DTXSD(new ClothesFactory());
        // 传入该动态代理对象要代理的目标对象
        ClothesFactory clothesFactory=new ClothesFactory();
        DTXSD dtxsd1=new DTXSD(clothesFactory);

        ShoeFactory shoeFactory=new ShoeFactory();
        DTXSD dtxsd2=new DTXSD(shoeFactory);
    }

}
内存图

在动态代理当中,我们不需要特意创建对象,反射会使创建对象的方式有很多种,不需要额外创建对象。

package DaiLi;

public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {

       //实现一个动态代理对象代理一个目标对象的方法
        //方法1
        // DTXSD dtxsd1=new DTXSD(new ClothesFactory());
        // 新建目标对象,传入该动态代理对象要代理的目标对象
//        ClothesFactory clothesFactory=new ClothesFactory();
//        DTXSD dtxsd1=new DTXSD(clothesFactory);

//        ShoeFactory shoeFactory=new ShoeFactory();
//        DTXSD dtxsd2=new DTXSD(shoeFactory);
        //方法2
        DTXSD dtxsd1=new DTXSD(ShoeFactory.class);//获取类对象,再创建对象
    }

}
package DaiLi;

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

public class DTXSD {
    private Object object;  //目标类
    public DTXSD(Class o) throws InstantiationException, IllegalAccessException {
        object=o.newInstance();//创建对象
    }


}
2.如何完成相关的调用工作,实现相关的接口
a.代理类当中实现该方法知道目标类当中的核心方法是什么
//动态代理实现相关接口
//调用该方法知道目标类当中的核心方法是什么
public Object getProxyInstance(){
    return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
    //object.getClass()获取目标类的类对象.getInterfaces()获取当前目标类的接口
    //object.getClass()获取目标类的类对象.getClassLoader()获取当前目标类的构造器
    //this代表当前对象,即代理对象
}
b.测试类调用该方法,知道核心方法是什么
ClothesFactory clothesFactory=new ClothesFactory();
        //调用方法。获取目标类接口,知道核心方法
        //1.
//        DTXSD dtxsd1=new DTXSD(clothesFactory);
//        dtxsd1.getProxyInstance();
        //2.
        DTXSD dtxsd1= (DTXSD) new DTXSD(clothesFactory).getProxyInstance();//强制类型转化
        
c.对核心方法进行调用

代理类实现 InvocationHandler接口,通过重写invoke方法对核心方法进行调用。

用接口接收获悉的核心方法

为什么用接口?

调用核心方法的方式有两种:

1.目标类对象直接调用,这会使用户可以直接访问核心方法,会造成一定的影响

2.通过接口调用

实现动态代理代码
package DaiLi;

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

public class DTXSD implements InvocationHandler {
    private Object object;  //目标类
    public DTXSD(Object o){
        object=o;
    }
    //动态代理实现相关接口
    //调用该方法知道目标类当中的核心方法是什么
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
        //object.getClass()获取目标类的类对象.getInterfaces()获取当前目标类的接口
        //object.getClass()获取目标类的类对象.getClassLoader()获取当前目标类的构造器
        //this代表当前对象,即代理对象
    }
    //
    //通过invoke方法对核心方法进行调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       method.invoke(object,args);
        return null;
        //三个参数的讲解
        //1.Object:jdk创建的代理类,无需赋值
        //2.Method:目标类当中的方法,jdk提供,无需赋值
        //3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值

    }
}
package DaiLi;

public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {

       //实现一个动态代理对象代理一个目标对象的方法
        //方法1
        // DTXSD dtxsd1=new DTXSD(new ClothesFactory());
        // 新建目标对象,传入该动态代理对象要代理的目标对象
        ClothesFactory clothesFactory=new ClothesFactory();
        DTXSD dtxsd1=new DTXSD(clothesFactory);
        Clothes clothes= (Clothes) dtxsd1.getProxyInstance();//用接口接收核心方法
        clothes.BuyClothes("XL");
        ShoeFactory shoeFactory=new ShoeFactory();
        DTXSD dtxsd2=new DTXSD(shoeFactory);
        Shoes shoes= (Shoes) dtxsd2.getProxyInstance();
        shoes.BuyShoes("39");
        }

}
运行结果

完整代码

测试类

package DaiLi;

public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {

       //实现一个动态代理对象代理一个目标对象的方法
        //方法1
        // DTXSD dtxsd1=new DTXSD(new ClothesFactory());
        // 新建目标对象,传入该动态代理对象要代理的目标对象
        ClothesFactory clothesFactory=new ClothesFactory();
        DTXSD dtxsd1=new DTXSD(clothesFactory);
        Clothes clothes= (Clothes) dtxsd1.getProxyInstance();//用接口接收核心方法
        clothes.BuyClothes("XL");
        ShoeFactory shoeFactory=new ShoeFactory();
        DTXSD dtxsd2=new DTXSD(shoeFactory);
        Shoes shoes= (Shoes) dtxsd2.getProxyInstance();
        shoes.BuyShoes("39");
        }

}

动态代理类

package DaiLi;

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

public class DTXSD implements InvocationHandler {
    private Object object;  //目标类
    public DTXSD(Object o){
        object=o;
    }
    //动态代理实现相关接口
    //调用该方法知道目标类当中的核心方法是什么
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
        //object.getClass()获取目标类的类对象.getInterfaces()获取当前目标类的接口
        //object.getClass()获取目标类的类对象.getClassLoader()获取当前目标类的构造器
        //this代表当前对象,即代理对象
    }
    //
    //通过invoke方法对核心方法进行调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(object,args);
        fuwu();
        return null;
        //三个参数的讲解
        //1.Object:jdk创建的代理类,无需赋值
        //2.Method:目标类当中的方法,jdk提供,无需赋值
        //3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值

    }
    private void fuwu(){
        System.out.println("销售店的售后服务");
    }
}

代码执行流程

1. 初始化阶段

首先,Test类的main方法被调用,这是程序的入口点。

2. 创建动态代理对象

ClothesFactory clothesFactory = new ClothesFactory();:创建了一个ClothesFactory对象,这个对象实现了Clothes接口,用于定制衣服。

DTXSD dtxsd1 = new DTXSD(clothesFactory);:创建了一个DTXSD对象,这是动态代理的实现类。DTXSD实现了InvocationHandler接口,并且在构造函数中接收一个Object参数,这个参数实际上是目标类的实例(这里是ClothesFactory对象)。

3. 创建代理对象

Clothes clothes = (Clothes) dtxsd1.getProxyInstance();:通过getProxyInstance()方法创建了一个代理对象,这个方法使用了Proxy.newProxyInstance()。这个方法接收三个参数:

object.getClass().getClassLoader():类加载器,用于创建代理类。

object.getClass().getInterfaces():目标类实现的接口列表,这里是Clothes接口。

this:当前的DTXSD对象,作为InvocationHandler。

用接口接收目标类的核心方法

4. 调用代理对象的方法

clothes.ByClothes("XL");:调用代理对象的ByClothes方法,参数是"XL"。调用接口中的方法,由于接口中的方法只有定义,因此会调用目标类当中的方法,从而实现代理。实际上,这个调用会通过代理对象调用DTXSD对象的invoke方法。

5. invoke方法的执行

在invoke方法中:

method.invoke(object, args):调用目标类(ClothesFactory)的ByClothes方法,传入参数"XL"。

fuwu();:执行代理类内部的fuwu方法,打印一条服务消息。

较为浅显易懂的解释

1.首先main方法入栈

2.创建一个目标类对象clothesFactory

3.clothesFactory对象当中有一个Buyclothes方法

4.该对象实现了Clothes接口,接口中有对Buyclothes方法的定义

5.创建一个动态代理对象dtxsd1

6.该对象中有一个object类型的变量,变量指向clothesFactory对象的地址

7.动态代理对象中有getProxyInstance() .invoke()并且实现InvocationHandler接口

8.调用动态代理对象的getProxyInstance()方法,获取目标类所定义的核心方法

9.接口调用Buyclothes方法,实际会调用clothesFactory中的Buyclothes方法,是一个方法重写的过程

10会执行invoke方法中的内容

欢迎大家点赞,收藏,评论加关注呦

标签:JAVA,对象,代理,DTXSD,-----,new,方法,public
From: https://blog.csdn.net/2301_81453175/article/details/141907118

相关文章

  • GitHub每周最火火火项目(9.2-9.8)
    项目名称:polarsource/polar项目介绍:polar是一个开源项目,它是LemonSqueezy的替代方案,并且具有更具优势的价格。该项目的目标是为开发者提供一种更好的选择,让他们能够在追求自己的热情和兴趣的同时,通过编码获得相应的报酬。通过使用polar,开发者可以享受到更实惠的价格......
  • 个人项目-论文查重
    这个作业属于哪个课程班级链接这个作业要求在哪里个人项目-作业-计科22级12班-班级博客-博客园(cnblogs.com)这个作业的目标准备、创建、开发、管理、测试个人项目GitHub项目链接https://github.com/chocohQL/3122004348-01可运行jar已发布在最新......
  • MaPLe(论文解读): Multi-modal Prompt Learning
    Comment:AcceptedatCVPR2023摘要预训练的视觉语言模型(VL-PTMs)(比如CLIP)在下游任务中已经表现出不错的泛化能力。但是它们对输入文本提示模板的选择很敏感,需要仔细选择提示模板才能表现良好。受到NLP领域的启发,最近的CLIP的自适应性方法开始学习提示作为文本输入,来微调CLIP......
  • TPT(论文解读):Test-Time Prompt Tuning for Zero-Shot Generalization in Vision-Langua
    Comment:NeurIPS2022视觉语言模型中用于zero-shot泛化的测试期间提示调优摘要预训练的视觉语言模型在许多具有恰当文本提示的下游任务中表现出不错的zero-shot泛化。最近的研究并非使用手动设计的提示,而是使用下游任务中的训练数据来学习提示。虽然这种方法是有效的,但是......
  • data-analysis-llm-agent
    data-analysis-llm-agenthttps://github.com/fanqingsong/data-analysis-llm-agentConversationalAIwithFunctionCallingforDataAnalysisOverviewThechatbotisdesignedtoprovidedataanalysisinsightsfromdatabasebasedonapredefinedschema.It......
  • 【Java】Word题库解析2
     初稿见:https://www.cnblogs.com/mindzone/p/18362194一、新增需求在原稿题库之后,还需要生成一份纯题目+ 纯答案答案放在开头,题目里面去掉答案在检查题型时还发现部分内容略有区别: 所以在判断是否为答案的时候需要兼容这种答案二、关于老版本支持doc2000版需要追加......
  • Clang-format格式标准化
    1,工具与准备:VScode中可以安装clang-format扩展或者使用C/C++;  2,配置VScode设置中,首选项->设置;可使用everythin搜索clang-format.exe;一般visualstudio会自带,选择一个即可(在环境变量中,添加对应的路径);    3,配置.clang-format中断使用以下命令创建.clang-form......
  • 视野修炼-技术周刊第100期 | CSS observer
    欢迎来到第100期的【视野修炼-技术周刊】,下面是本期的精选内容简介......
  • 1-4Java修饰符
    Java修饰符Java语言提供了很多修饰符,主要分为以下两类:访问修饰符非访问修饰符修饰符用来定义类,方法或者变量,通常放在语句的最前端。访问控制修饰符Java中,可以使用访问控制符来保护对类,方法,变量,构造方法的访问。Java支持4种不同的访问权限。default(即默认,什么也不写):在......
  • VoceChat - 发现私有云社交的魅力
    VoceChat使用反馈:发现私有云社交的魅力 在这个信息浩如烟海的时代,如何保持有效的沟通与信息共享,成为了我们每一个人都需要面对的挑战。很高兴在这段时间里,体验了VoceChat这款支持独立部署的个人云社交媒体聊天服务。作为一个高度灵活且保护用户数据隐私的通讯工具,VoceChat的表......