(Java笔记)JDK动态代理

目录

一、什么是动态代理?

二、JDK动态代理

三、JDK动态代理用到的类和接口

        (1)Proxy类

        (2)Method类

        (3)InvocationHandler接口

四、JDK动态代理实现

        (1)定义业务接口

        (2)接口实现——>刘德华+周润发

        (3)JDK动态代理工厂类

        (4)junit代码测试JDK动态代理

五、总结


一、什么是动态代理?

        动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java源文件——>jdk运行期间动态创建class字节码并加载JVM——>代理对象在程序运行的过程中动态在内存构建,可以灵活的进行业务功能的切换。


二、JDK动态代理

  A.目标对象必须实现业务接口。
  B.JDK代理对象不需要实现业务接口。
  C.JDK动态代理的对象在程序运行前不存在,在程序运行时动态的在内存中构建。
  D.JDK动态代理灵活的进行业务功能的切换。
  E.本类中的方法(非接口中的方法)不能被代理。


三、JDK动态代理用到的类和接口

        (1)Proxy类

通过JDK的java.lang.reflect.Proxy类实现动态代理,会使用其静态方法newProxyInstance(),依据目标对象、业务接口及调用处理器三者,自动生成一个动态代理对象。

        public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)

        loader:目标类的类加载器,通过目标对象的反射可获取

        interfaces:目标类实现的接口数组,通过目标对象的反射可获取

        handler:调用处理器。


        (2)Method类

        反射用的类,用来进行目标对象的方法的反射调用。
        method对象接住我们正在调用的方法sing(),show()
        method——>sing(),show()
        method.invoke();==>手工调用目标方法  sing();   show();

        invoke()方法的第二个参数为Method类对象,该类有一个方法也叫invoke(),可以调用目标方法。这两个invoke()方法,虽然同名,但无关。

        public Object invoke ( Object obj, Object... args)

        obj:表示目标对象

        args:表示目标方法参数

        args就是其上一层invoke方法的第三个参数,invoke方法的作用是:调用执行obj对象所属类的方法,这个方法由其调用者Method对象确定。在代码中,一般的写法为method.invoke(target, args);其中,method为上一层invoke方法的第二个参数。这样,即可调用了目标类的目标方法。


        (3)InvocationHandler接口

         它是实现代理和业务功能的,我们在调用时使用匿名内部实现。

        InvocationHandler接口叫做调用处理器,负责完成调用目标方法,并增强功能。通过代理对象执行目标接口中的方法,会把方法的调用分派给调用处理器(InvocationHandler)的实现类,执行实现类中的invoke()方法,我们需要把功能代理写在invoke()方法中。

        InvocationHandler此接口中只有一个invoke()方法。

         InvocationHandler源码

package java.lang.reflect;

public interface InvocationHandler {

    /**
     * InvocationHandler是由代理实例的调用处理程序实现的接口。 每个代理实例都有一个关联的调用处
     * 理程序。在代理实例上调用方法时,方法调用将被编码并调度到其调用处理程序的invoke方法
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

         在invoke方法中可以截取对目标方法的调用。在这里进行功能增强。Java的动态代理是建立在反射机制之上的。实现了InvocationHandler接口的类用于加强目标类的主业务逻辑。这个接口中有一个方法invoke(),具体加强的代码逻辑就是定义在该方法中的。通过代理对象执行接口中的方法时,会自动调用invoke()方法。

        invoke()方法的介绍如下:

                public Object invoke ( Object proxy, Method method, Object[] args)

        A.proxy:代表生成的代理对象

        B.method:代表目标方法

        C.args:代表目标方法的参数

        第一个参数proxy是jdk在运行时赋值的,在方法中直接使用,第二个参数后面介绍,第三个参数是方法执行的参数,这三个参数都是jdk运行时赋值的,无需程序员给出。


四、JDK动态代理实现

        A.代理对象不需要实现接口

        B.代理对象的生成是利用JDK包API中的Proxy类,动态的在内存中构建代理对象。

        (1)定义业务接口

public interface Service {
    //唱歌
    void sing();
    //展示年龄
    String showAge (int age);
}

        (2)接口实现——>刘德华+周润发

//目标对象
public class SuperStarLiu implements Service {
    
    @Override
    public void sing() {
        System.out.println("刘德华正在唱歌");
    }

    @Override
    public String showAge(int age) {
        return "刘德华有" + age + "岁";
    }
}
//目标对象
public class SuperSatZhou implements Service {

    @Override
    public void sing() {
        System.out.println("周润发正在唱歌");
    }

    @Override
    public String showAge(int age) {
        return "周润发有" + age + "岁";
    }
}

        (3)JDK动态代理工厂类

        本类中的方法(非接口中方法)不能被代理

public class ProxyFactory {

    //类中成员变量声明为接口
    public Service target;//目标对象

    //传入目标对象,方法设计为接口
    public ProxyFactory(Service target) {
        this.target = target;
    }

    //调用处理程序,返回指定接口的代理类实例(动态代理对象)
    public Object getAgent() {
        // 处理代理实例(代理对象)上的方法调用并返回结果(目标对象)。
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //指定当前目标对象,使用类加载器获得
                target.getClass().getInterfaces(),//获得目标对象实现的所有接口
                new InvocationHandler() { //处理代理实例上的方法并返回调用结果
                    @Override
                    public Object invoke(
                            Object proxy, //代理对象的实例
                            Method method,//代理的目标对象的实现方法
                            Object[] args) throws Throwable { //代理的目标对象实现方法的参数
                        System.out.println("预订时间");
                        System.out.println("预订场地");
                        //目标对象通过调用反射自动执行自己的方法
                        Object returnValue = method.invoke(target, args);//sing(),show(args)
                        System.out.println("结算费用");

                        return returnValue;//返回目标对象执行方法的返回值
                    }
                });
    }
}

        (4)junit代码测试JDK动态代理

    @Test
    public void test1() {
        ProxyFactory proxyFactory = new ProxyFactory(new SuperSatZhou());
        Service agent = (Service) proxyFactory.getAgent();
        agent.sing();
    }

    @Test
    public void test2() {
        ProxyFactory proxyFactory = new ProxyFactory(new SuperSatZhou());
        Service agent = (Service) proxyFactory.getAgent();
        System.out.println(agent.showAge(25));
    }

   @Test
    public void test3() {
        ProxyFactory proxyFactory = new ProxyFactory(new SuperStarLiu());
        Service agent = (Service) proxyFactory.getAgent();
        System.out.println(agent.showAge(50));
        System.out.println(agent.getClass());//动态代理类型:class com.sun.proxy.$Proxy2
    }

        补充:在业务接口Service中,可以根据需求增加业务功能,同时实现类也相应的重写方法,编写具体业务功能代码,而JDK代理工厂类不做任何改动,当调用运行时,会自动执行对应的方法,最终成为$Proxy类型的代理对象。


五、总结

仅自己学习记录,如有错误,敬请谅解~,谢谢~~~

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电竞丶小松哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值