Java的静态代理与jdk动态代理

代理

我们经常利用代理进行解耦以及控制对实际对象的访问等工作。例如,我们可以通过代理对方法的调用进行更精细的控制(例如加上日志、权限控制等),而无需修改实际对象的代码。代理的作用是无侵入式的给代码增加功能。有些事情是对象不想做或者不能做的,就可以通过代理来实现。
代理一般有三种模式:

  1. 静态代理
  2. jdk动态代理
  3. cglib动态代理(这里不做过多赘述)

静态代理

静态代理很简单,我们通过代码来理解就很方便。

package TestProcxy;

public class ProTest {
    public static void main(String[] args) {
        Father father = new Father();
        father.eat();
    }
}

class Per{
    public void eat(){
        System.out.println("吃饭!!!");
    }
}

class Father{
    Per per = new Per();
    public void eat(){
        System.out.println("拿筷子~~~~");
        per.eat();
        System.out.println("洗碗~~~~");
    }
}

运行结果
![[Pasted image 20240329095713.png]]

jdk动态代理

代理里面就是对象要被代理的方法。java通过接口来保证代理的样子,即对象和代理要实现同一个接口中的方法就是被代理的所有方法。
代理可以增强或者拦截的方法都在接口中,接口需要写在newProxyInstance的第二个参数里。

package TestProxy;

/**
 * 接口
 * 通过接口来进行代理
 */
public interface Event {
    void eat(String something);
}


package TestProxy;

public class Per implements Event {
    String name;

    public Per(String name) {
        this.name = name;
    }
    @Override
    public void eat(String something) {
        System.out.println(name + "吃" + something + "!!!");
    }
}


package TestProxy;

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

public class PerProxy {
    public static Event createProxy(){
        /**
         * java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
         * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
         * 参数一:用于指定用哪个类加载器去加载生成的代理类
         * 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
         * 参数三:用来指定生成的代理对象要干什么事情
         */
        Object o = Proxy.newProxyInstance(
                PerProxy.class.getClassLoader(),
                new Class[]{Event.class},
                new InvocationHandler() {
                    /*
                     * 参数一:代理的对象
                     * 参数二:要运行的方法 eat
                     * 参数三:调用eat方法时,传递的实参
                     * */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("拿筷子~~~");
                        method.invoke(new Per("张三"), args);
                        System.out.println("洗碗~~~");
                        return null;
                    }
                });
        return (Event) o;
    }
}


package TestProxy;

public class ProTest {
    public static void main(String[] args) {
        PerProxy perProxy = new PerProxy();
        Event proxy = perProxy.createProxy();
        proxy.eat("刀削面");
    }
}

运行结果
![[Pasted image 20240329110824.png]]

练习

对List的add方法进行增强,对remove方法进行拦截。

package TestProxy;

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

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

        List list = new ArrayList();
        Object o = Proxy.newProxyInstance(EnhanceList.class.getClassLoader(), new Class[]{List.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 对原List的add方法进行增强
                if (method.getName().equals("add")) {
                    System.out.println("对list新增了" + args[0]);
                    return method.invoke(list, args);
                } else if (method.getName().equals("remove")) {
                    // 拦截根据索引删除的方法是正常的,如果拦截根据对象删除的方法就会报错,因为他们的返回值不一样
                    System.out.println("拦截了remove方法");
                    return null;
                } else {
                   return method.invoke(list, args);
                }
            }
        });
        List proxyList = (List) o;
        proxyList.add("aaa");
        proxyList.add("bbb");
        proxyList.add("ccc");
        proxyList.add("ddd");

        proxyList.remove(0);
        proxyList.remove("aaa");
        System.out.println(list);
    }
}

这段代码是由问题的就是在拦截remove方法时的问题,因为remove重载了两种方法,返回值类型也不一样(一个是布尔类型,另一个是对象),而我们在拦截时只返回了null,因此会报错。
运行结果
![[Pasted image 20240329114907.png]]

正确的修改
![[Pasted image 20240329115006.png]]

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值