0
点赞
收藏
分享

微信扫一扫

动态代理的实现过程(jdk)

Resin_Wu 2022-03-12 阅读 69
代理模式

 代理对象和真实对象必须实现同一个接口

API介绍

Proxy

  • 使用JDK的动态代理的要求:目标对象必须实现了接口。

  • 相关类:JDK的类java.lang.reflect.Proxy,提供了生成代理对象的方法

  • 生成代理对象的方法: Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h)

    • loader:类加载器

    • interfaces:目标对象所实现的接口 字节码数组

    • h:用于写代理对象要做的事情,通常写成InvocationHandler接口的匿名内部类,实现其invoke方法

InvocationHandler接口

  • 接口只有一个方法:每次当代理对象被调用时,这个方法都会执行。在方法里通常写代理对象的行为 invoke(Object proxy, Method method, Object[] args)

  • 方法的参数:

    • Object proxy:最终生成的代理对象

    • Method method:用户在调用代理对象时,所执行的方法对象

    • Object[] args:用户在调用代理对象,执行方法时,所传递的实参

  • 方法的返回值:

    • 当用户调用的代理对象的方法后,得到的返回值

使用示例

1.同一个接口

package com.dian.proxy.jdk;

//真是对象,代理对象的共同接口
public interface Star {
    void sing(String name);

    void dance(String name);
}

2.实现类

package com.dian.proxy.jdk;
//真实对象的方法
public class SuperStar implements Star {
    public void sing(String name) {
        System.out.println("明星在唱歌:" + name);
    }

    public void dance(String name) {
        System.out.println("明星在跳舞:" + name);

    }
}

3.有通知类(用于进行功能增强的)

package com.dian.proxy.jdk;

//这里是可以增强真实对象的方法
public class StarAdvice {
    public void before() {
        System.out.println("彩排一下~!");
    }

    public void after() {
        System.out.println("收钱~!");
    }
}

4.使用动态代理生成代理对象

package com.dian.proxy.jdk;

import org.junit.Test;

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

public class TestJDKProxy {
    @Test
    public void testJDK() {
        //1.创建真实对象
        final Star realObj = new SuperStar();
        //2.创建代理对象 只是在外人面前是代理对象在干活,实际上还是真实对象在干活

        Star proxyObj = (Star) Proxy.newProxyInstance(
                realObj.getClass().getClassLoader(),    //真实类使用什么类加载器,代理类也使用什么类加载器
                realObj.getClass().getInterfaces(),  //真实对象用什么接口,代理对象也用什么接口
                new InvocationHandler() {  //调用处理器是代理对象和真实对象沟通的桥梁
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        // System.out.println("调用了invoke方法~");
                        /*
                            在这里让真实对象干活
                         */

                          /*
                        invoke方法: 当我们在外面使用代理对象调用任何方法,这个invoke方法都会被调用一次。
                            proxy : 代理对象
                           method : 外面调用的那个方法的对象,
                                proxyObj.sing("忘情水");  ====  method 就是sing方法
                           args :表示方法参数,表示外面调用的方法用到的参数
                                 proxyObj.sing("忘情水"); ====  args : 忘情水
                     */

                        //调用方法之前增强
                        StarAdvice sa = new StarAdvice();
                        sa.before();

                        //为了匹配任意情况,所以这里必须要用反射调用。
                        Object object = method.invoke(realObj, args);

                        //调用方法之后,增强
                        sa.after();

                        return object;
                    }
                }
        );
        //3. 让代理唱歌,跳舞
        proxyObj.dance("极乐净土");

    }
}
举报

相关推荐

0 条评论