关于动态代理的学习

本文通过实例解析Java静态代理与动态代理的工作原理,展示了如何使用代理模式简化类的扩展,重点讲解了动态代理的StuInvocationHandler实现和Proxy.newProxyInstance方法的应用。

今天看面经看到了这里,上网找了些资料,没太看懂,就照着资料上的代码自己动手写了点,这里记录一下我的学习过程。

java动态代理实现与原理详细分析 - Gonjian - 博客园

java动态代理实现_luu_一只程序猿的博客-优快云博客_java动态代理

我主要就是照着这两个写的。

之后的内容有极大可能出错(因为是我个人的感悟),欢迎指正。

首先是静态代理的一点内容

先是一个接口

public interface Person {
    //上交班费
    void giveMoney();
}

然后是实现类

public class Student implements Person{
    private String name;
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void giveMoney() {
        System.out.println(name + "上交班费50元");
    }
}

实现类的代理类

public class StudentsProxy implements Person{
    //被代理的学生
    Student stu;

    public StudentsProxy(Person stu) {
        // 只代理学生对象
        if(stu.getClass() == Student.class) {
            this.stu = (Student)stu;
        }
    }

    //代理上交班费,调用被代理学生的上交班费行为
    public void giveMoney() {
        System.out.println("我帮你交钱吧");
        stu.giveMoney();
    }
}

测试的代码

        //被代理的学生张三,他的班费上交有代理对象monitor(班长)完成
        Person zhangsan = new Student("张三");

        //生成代理对象,并将张三传给代理对象
        Person monitor = new StudentsProxy(zhangsan);

        zhangsan.giveMoney();
        //班长代理上交班费
        monitor.giveMoney();
        System.out.println("---------------------------------------------------");

结果

张三上交班费50元
我帮你交钱吧
张三上交班费50元

静态代理就这么结束了。很简单。

然后是动态代理的一部分

动态代理的实现类(或者叫代理类?)

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

public class StuInvocationHandler <T> implements InvocationHandler {
    //invocationHandler持有的被代理对象
    T target;

    public StuInvocationHandler(T target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" +method.getName() + "方法");
        
        Object result = method.invoke(target, args);
        return result;
    }
}

测试代码(这里用的是比较繁琐的那一套,不建议使用,我的idea里面getProxyClass这个方法加了横线,应该是属于过时的方法)

        InvocationHandler stuHandler2 = new StuInvocationHandler<Person>(zhangsan);
        Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[] {Person.class});
        Constructor<?> constructor = stuProxyClass.getConstructor(InvocationHandler.class);
        Person stuProxy2 = (Person) constructor.newInstance(stuHandler2);
        stuProxy2.giveMoney();

结果

代理执行giveMoney方法
张三上交班费50元

这样看其实动态代理并没有什么很大的改进,不过我后来意识到,静态代理的话需要每一个类写一个代理类,动态代理有一个就够了。

我又写了个Person 的实现类

public class poorStudent implements Person{
    private String name;
    public poorStudent(String name) {
        this.name = name;
    }
    @Override
    public void giveMoney() {
        System.out.println(name + "上交班费5元");
    }
}

静态代理的话就需要针对这个类再写一个代理类,动态代理不用

以下是测试代码

        poorStudent lisi=new poorStudent("李四");
        //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler stuHandler = new StuInvocationHandler<Person>(lisi);

        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

        //代理执行上交班费的方法
        stuProxy.giveMoney();
        System.out.println("---------------------------------------------------");

结果

代理执行giveMoney方法
李四上交班费5元

总的测试代码

//被代理的学生张三,他的班费上交有代理对象monitor(班长)完成
        Person zhangsan = new Student("张三");

        //生成代理对象,并将张三传给代理对象
        Person monitor = new StudentsProxy(zhangsan);

        zhangsan.giveMoney();
        //班长代理上交班费
        monitor.giveMoney();
        System.out.println("---------------------------------------------------");
        //---------------------------------------------------
        poorStudent lisi=new poorStudent("李四");
        //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler stuHandler = new StuInvocationHandler<Person>(lisi);

        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

        //代理执行上交班费的方法
        stuProxy.giveMoney();
        System.out.println("---------------------------------------------------");
        //---------------------------------------------------
        InvocationHandler stuHandler2 = new StuInvocationHandler<Person>(zhangsan);
        Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[] {Person.class});
        Constructor<?> constructor = stuProxyClass.getConstructor(InvocationHandler.class);
        Person stuProxy2 = (Person) constructor.newInstance(stuHandler2);
        stuProxy2.giveMoney();

结果

张三上交班费50元
我帮你交钱吧
张三上交班费50元
---------------------------------------------------
代理执行giveMoney方法
李四上交班费5元
---------------------------------------------------
代理执行giveMoney方法
张三上交班费50元

在有很多类要代理的时候,动态代理可以少写很多代码

(代码复用率更高?好像是这么说的)


我又测试了换个接口的实现类

接口和实现类

public interface Teacher {
    //收到班费
    void getMoney();
}
public class headmaster implements Teacher{
    private String name;
    public headmaster(String name) {
        this.name = name;
    }
    @Override
    public void getMoney() {
        System.out.println(name + "领取班费55元");
    }
}

测试代码

        headmaster wangwu=new headmaster("王五");
        //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler teaHandler = new StuInvocationHandler<Teacher>(wangwu);

        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Teacher teaProxy = (Teacher) Proxy.newProxyInstance(Teacher.class.getClassLoader(), new Class<?>[]{Teacher.class}, teaHandler);

        //代理执行上交班费的方法
        teaProxy.getMoney();

结果

代理执行getMoney方法
王五领取班费55元

可以看出,不光是同一个接口的不同实现类,不同接口的实现类也可以用同一个代理类来进行动态代理(好绕口……),如果是静态代理的话就需要创建多个代理类才行。

就到这里(有相当部分部分代码是人家的,不过我自己也写了些,人家的地址我也放开头了,这里就先投原创了,有问题的话可以留言联系我)。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值