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

什么是代理

代理本身是一种设计模式

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

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方法中的内容

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

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值