动态代理

什么是动态代理?

csharp 复制代码
public class Student {
    public void eat() {
        System.out.println("吃饭")
    }
}

现在我们想给eat方法增加一些东西,让吃饭这个动作更加完整

csharp 复制代码
public class Student {
    public void eat() {
        System.out.println("拿筷子");
        System.out.println("盛饭");
        System.out.println("吃饭");
    }
}

这种修改叫做侵入式修改。在一个成熟的项目中,我们很少会这么修改,容易引发一系列连锁问题。

那么问题来了,我现在不能修改原有的代码,又要增加额外的功能,该如何实现?

此时我们可以找一个代理,即一个中介公司,它会先做拿筷子和盛饭这两个动作,等真正吃饭了再调用Student的eat方法吃饭,这就是动态代理,它可以无侵入式地给代码增加额外的功能。可以理解为明星的经纪人。

对象有什么方法想被代理,代理就一定要有对应的方法。代理中对应的方法会先把其它事情做完,再调用原来对象中的方法。

中介如何知道要派有对应方法的代理?这需要通过接口来解决。把被代理的方法写在接口中,让代理和对象都实现这个接口。

arduino 复制代码
public class BigStar implements Star{
    private String name;
​
    public BigStar(String name) {
        this.name = name;
    }
​
    public BigStar() {
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    @Override
    public String toString() {
        return "BigStar{" +
                "name='" + name + ''' +
                '}';
    }
​
    //唱歌和跳舞
    @Override
    public String sing(String name) {
        System.out.println(this.name + "正在唱" + name);
        return "谢谢";
    }
​
    @Override
    public void dance() {
        System.out.println(this.name + "正在跳舞");
    }
}
csharp 复制代码
public interface Star {
​
    //把所有想要代理的方法定义在接口中
    //唱歌和跳舞
    public abstract String sing(String name);
​
    public abstract void dance();
}

java.lang.reflect.proxy类提供了为对象产生代理对象的方法

vbnet 复制代码
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

参数一:用于指定用哪个类加载器,去加载生成的代理类。

参数二:指定接口,这些接口用于指定生成的代理有哪些方法

参数三:指定生成的代理对象要干什么事情

类加载器负责将字节码文件加载到内存当中,通过getClassLoader方法找到是谁把当前这个类的字节码文件加载到内存的。

csharp 复制代码
public interface Star {
​
    //把所有想要代理的方法定义在接口中
    //唱歌和跳舞
    public abstract String sing(String name);
​
    public abstract void dance();
}
arduino 复制代码
public class BigStar implements Star{
    private String name;
​
    public BigStar(String name) {
        this.name = name;
    }
​
    public BigStar() {
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    @Override
    public String toString() {
        return "BigStar{" +
                "name='" + name + ''' +
                '}';
    }
​
    //唱歌和跳舞
    @Override
    public String sing(String name) {
        System.out.println(this.name + "正在唱" + name);
        return "谢谢";
    }
​
    @Override
    public void dance() {
        System.out.println(this.name + "正在跳舞");
    }
}
csharp 复制代码
public class ProxyUtil {
    //创建一个代理
​
    //给一个明星对象创建一个代理
    //形参:被代理的明星对象,要知道给谁做代理
    //返回值:给明星创建的代理
    public static Star createProxy(BigStar bigStar) {
​
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},//将接口的字节码放在数组中,这些接口用于指定代理长什么样,也就是中介能代理哪些方法,如果有多个接口可以把它们都写在数组中
                new InvocationHandler() { //指定生成的代理要做什么
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //参数一:代理的对象
                        //参数二:要运行的方法
                        //参数三:方法参数
                        if("sing".equals(method.getName())) {
                            System.out.println("准备话筒,收钱");
                        } else if ("dance".equals(method.getName())) {
                            System.out.println("准备场地,收钱");
                        }
                        //去找大明星开始唱歌或跳舞
                        //代码里的表现形式:调用大明星里的唱歌或跳舞方法
                        return method.invoke(bigStar,args);//反射
                    }
                }
        );
​
        return star;
    }
}
​
java 复制代码
public class test {
    public static void main(String[] args) {
        //需求:粉丝想要大明星唱一首歌
        //1.获取代理的对象:代理对象 = ProxyUtil.createProxy(大明星的对象)
        //2.再调用代理的唱歌方法,此时会运行invoke
​
        //1.获取代理的对象
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);
​
        //2.调用唱歌方法
        String res = proxy.sing("只因你太美");
        System.out.println(res);
    }
}

重点在于理解创建代理的代码。可以理解为给明星配置一个经纪人。

相关推荐
Knight_AL2 小时前
Spring 事务管理:为什么内部方法调用事务不生效以及如何解决
java·后端·spring
4***17273 小时前
Spring Boot中Tomcat配置
java
Chan163 小时前
场景题:CPU 100% 问题怎么排查?
java·数据库·redis·后端·spring
qq_336313934 小时前
java基础-IO流(网络爬虫/工具包生成假数据)
java·爬虫·php
桦说编程4 小时前
滑动窗口限流器的演进之路:从调度器实现到 Packed CAS
java·后端·性能优化
开开心心_Every4 小时前
安卓后台录像APP:息屏录存片段,行车用
java·服务器·前端·学习·eclipse·edge·powerpoint
初次攀爬者4 小时前
SpringBoot 整合 JWT + Redis 实现登录鉴权
java·redis·后端
悦悦妍妍4 小时前
spring-ioc
java