java动态代理

java动态代理

概念:JDK提供的动态创建接口对象的方式,就叫动态代理

问题场景假设:

电脑上有浏览器Browser这种工具,而市面上实现了这种工具的产品主要有Chrome,现在,我也想做一个类似于Chrome的浏览器,并且实现我自己的功能.但是我不知道他是怎么做的,此时可以使用代理模式.

我们已知Browser是Chrome实现的接口,Chrome就是被代理的对象.既然Chrome实现了Browser接口,那就实现了Browser的所有方法,我们可以也实现Browser接口,来获取里面的方法,并传入一个Chrome对象,借用Chrome对象来实现方法

package Aop;

public interface Browser {
    public void open(String str);
    public void close();
}
package Aop.impl;

import Aop.Browser;
//这个类的内部实现应该是我们不知道的
public class Chrome implements Browser {
    @Override
    public void open(String str) {
        System.out.println("打开浏览器进行搜索:"+str);
    }

    @Override
    public void close() {
        System.out.println("关闭浏览器...");
    }
}

package Aop.impl;

import Aop.Browser;

public class  QQBrowser implements Browser {

    private Browser browser;

    public QQBrowser(Browser browser){
        this.browser=browser;
    }

    @Override
    public void open(String str) {
        //这里加入了自己的功能
        System.out.println("搜集用户信息,回传华强北");
        //通过browser对象来具体实现方法.
        browser.open(str);
        System.out.println("准备开始弹窗");
    }

    @Override
    public void close() {
        browser.close();
    }
}
    public static void main(String[] args) {
        Browser browser=new Chrome();
        QQBrowser qqBrowser = new QQBrowser(browser);
        qqBrowser.open("百度百科");
        qqBrowser.close();
    }

这种方法是静态代理,主要有两个缺点:

1.必须继承和盗窃类相同的接口,才能知道被盗取的类有什么功能

2.必须创建一个实体类文件

这样也太麻烦了,每一次创建一个实体类,有什么方法可以不创建实体类就获取到Browser的所有东西吗?

反射!动态代理就是基于反射机制完成的

    public static void main(String[] args) {
        Browser browser=new Chrome();
        /**
         * Proxy 动态代理类 属于java.lang.reflect包下,也就是反射包下
         * newProxyInstance常用的Proxy实例化方法
         * 参数:  ClassLoader  被代理类的加载器
         *       Interfaces    被代理类实现的接口
         *       InvocationHandler  调用处理器,具体的功能在这里实现
         */
        Browser ahou =(Browser) Proxy.newProxyInstance(browser.getClass().getClassLoader()
                , browser.getClass().getInterfaces(), new InvocationHandler() {
                    /**
                     *这里要做的是对被代理类进行功能扩展,每一次调用代理类ahou的方法时,都会调用一次invoke方法
                     * @param proxy 代理对象  Proxy
                     * @param method 代理方法
                     * @param args   方法参数
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object invoke = null;
                        if (method.getName()=="open"){
                            System.out.println("搜集用户信息,回传华强北");
                            invoke = method.invoke(browser, args);
                            System.out.println("准备开始弹窗");
                        }else{
                            invoke = method.invoke(browser, args);
                        }
                        return invoke;
                    }
                });
        ahou.open("百度百科");
//        ahou.close();
    }

这里可能会有一个疑惑,那就是proxy这个参数传进来有什么用呢?

我们看一下下面的动态代理的代码

package Aop.WhatisProxy;

public interface People {
    public People work(String workName);
}
package Aop.WhatisProxy;

public class Student implements People{

    @Override
    public People work(String workName) {
        System.out.println("工作内容是"+workName);
        return this;
    }
}
package Aop.WhatisProxy;

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

public class Test {

    public static void main(String[] args) {
        People people = new Student();
        People proxy = (People)Proxy.newProxyInstance(people.getClass().getClassLoader(),
                people.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object invoke = null;
                        System.out.println("before 动态代理...");
                        invoke = method.invoke(people, args);
                        System.out.println("after 动态代理...");
                        return invoke;
                    }
                });

        proxy.work("写代码").work("开会").work("上课");

    }
}

输出结果:

before 动态代理...
工作内容是写代码
after 动态代理...
工作内容是开会
工作内容是上课

这个例子中,我们同上面一样,实际上并没有用到proxy这个参数,我们可以看到,实际上进入invoke方法只有第一次调用work()方法的时候

我们把上面的代码改一下

package Aop.WhatisProxy;

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

public class Test {

    public static void main(String[] args) {
        People people = new Student();
        People proxy = (People)Proxy.newProxyInstance(people.getClass().getClassLoader(),
                people.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object invoke = null;
                        System.out.println("before 动态代理...");
                        invoke = method.invoke(people, args);
                        System.out.println("after 动态代理...");
                        return proxy;
                    }
                });

        proxy.work("写代码").work("开会").work("上课");

    }
}

这里将返回值改成了proxy

看一下输出:

before 动态代理...
工作内容是写代码
after 动态代理...
before 动态代理...
工作内容是开会
after 动态代理...
before 动态代理...
工作内容是上课
after 动态代理...

可以看到,现在每次都进到了invoke方法中.

产生不同情况的原因,我们可以通过proxy,people和invoke表示的类来理解一下

package Aop.WhatisProxy;

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

public class Test {

    public static void main(String[] args) {
        People people = new Student();
        People proxy = (People)Proxy.newProxyInstance(people.getClass().getClassLoader(),
                people.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object invoke = null;
                        System.out.println("before 动态代理...");
                        System.out.println(proxy.getClass().getName());
                        System.out.println(people.getClass().getName());
                        invoke = method.invoke(people, args);
                        System.out.println(invoke.getClass().getName());
                        System.out.println("after 动态代理...");
                        return proxy;
                    }
                });
        proxy.work("写代码").work("开会").work("上课");
    }
}
before 动态代理...
com.sun.proxy.$Proxy0
Aop.WhatisProxy.Student
工作内容是写代码
Aop.WhatisProxy.Student
after 动态代理...
before 动态代理...
com.sun.proxy.$Proxy0
Aop.WhatisProxy.Student
工作内容是开会
Aop.WhatisProxy.Student
after 动态代理...
before 动态代理...
com.sun.proxy.$Proxy0
Aop.WhatisProxy.Student
工作内容是上课
Aop.WhatisProxy.Student
after 动态代理...

从上面的输出代码可以明显看出,proxy是Proxy这个代理类,people自然就是被代理类Aop.WhatisProxy.Student,而invoke也是Aop.WhatisProxy.Student,是因为work方法返回的this就是Student类.

所以,如果在invoke()方法中返回的是invoke,那么只有 proxy.work(“写代码”)是用了代理类的方法,而proxy.work(“写代码”)返回了Aop.WhatisProxy.Student类,所以后面的.work(“开会”)和.work(“上课”)自然就调用了Aop.WhatisProxy.Student类中的work()方法.

如果返回的是proxy,那么就可以确保在这个链式调用中每次返回的都是代理类,既然是代理类那就是用的代理类中的invoke方法来实现Aop.WhatisProxy.Student类中的work()方法,而不是 直接使用Aop.WhatisProxy.Student类中的work()方法.

参考文章:
Java中Invoction类中第一个参数proxy的作用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值