前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java学习笔记(中级篇)—JDK动态代理

java学习笔记(中级篇)—JDK动态代理

作者头像
chlinlearn
发布2019-09-12 19:15:15
3220
发布2019-09-12 19:15:15
举报
文章被收录于专栏:java老实人

一、什么是代理模式

相信大家都知道代理商这个概念,在商业中,代理商无处不在。假设你要去买东西,你不可能去找真正的厂家去买,也不可能直接跟厂家提出需求,代理商就是这中间的一桥梁,连接买家和厂商。你要买或者定制什么产品,需要什么规格样式和价格的直接跟代理商沟通就好了,由代理商与真实的厂商沟通,这样买家有什么问题都可以咨询代理商,真实厂商也就可以专心做产品,不需要管其他事务了,买家也插手不了厂商的事。

在以上的关系中,厂商就是被代理对象,代理商就是代理对象,而买家就是调用者了。java中有多种动态代理的技术,包括JDK、CGLIB、Javassist等,这里我会拿CGLIB与JDK动态代理作比较。

二、意义

动态代理的意义就是在与生成一个占位(代理对象),来代理真实对象,从而达到控制真实对象的目的。要了解动态代理,首先要具备反射的知识。

三、实现动态代理的步骤

代理的实现分为两个主要步骤:

1.代理对象和真实对象建立代理关系

2.实现代理对象的逻辑方法

四、JDK动态代理

JDK动态代理,JDK自带的功能,在java.lang.reflect.*包中。要实现JDk动态代理,必须要借助接口才能产生代理对象。

1.先来定义一个简单的接口HelloWorld.java

代码语言:javascript
复制
public interface HelloWorld {
    void sayHello();
}

2.HelloWorld的实现类HelloWorldImpl.java

代码语言:javascript
复制
public class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHello() {
        System.out.println("hello world");
    }
}

3.建立代理关系,必须实现接口InvocationHandler。invoke是接口里唯一需要实现的方法,里面实现的代理逻辑,当代理对象调度方法时,就会映射到invoke方法来,实际是通过反射来实现的。而bind()方法就是建立代理关系,通过Proxy的newProxyInstance来创建代理对象,第一个参数类加载器,第二个参数下挂的接口,第三个参数则是实现了代理逻辑方法invoke的类。

代码语言:javascript
复制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy implements InvocationHandler {
    //真实对象
    private Object target = null;

    /**
     * 建立真实对象与代理对象之间的关系
     * @param target 传入真实对象
     * @return
     */
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance
            (target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }

    /**
     *  代理逻辑
     * @param proxy 代理对象
     * @param method 当前调度的方法
     * @param args 调度方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调用真实对象之前的服务");
        Object object = method.invoke(target,args);
        System.out.println("在调用真实对象之后的服务");
        return object;
    }
}

4.测试

代码语言:javascript
复制
import org.junit.Test;

public class JdkProxyTest {

    @Test
    public void test_JdkProxy(){
        JdkProxy proxy = new JdkProxy();
        HelloWorld helloWorld = null;
        try {
            helloWorld = (HelloWorld) proxy
                .bind(Class.forName
            ("com.xcl.ssm.chapter2.jdkproxy.HelloWorldImpl")
                            .newInstance());
        } catch (Exception e) {
            e.printStackTrace();
        }
        helloWorld.sayHello();
    }
}

五、CGLIB动态代理

上面说JDK动态代理的实现必须借助接口才能实现,而CGLIB则不用,只需要有一个非抽象类即可。我们以上面的HelloWorldImpl类为例,现在没有HelloWorld接口了。JDK动态代理必须要实现invocationHandler接口,CGLIB则必须要实现MethodInterceptor接口,里面也只有一个需要实现的方法intercept(),需要在里面实现代理逻辑。写代码之前记得导包哦,这是第三方提供的技术。

代码语言:javascript
复制
public class CglibProxy implements MethodInterceptor {

    /**
     *  生成CGLIB代理对象
     * @return
     */
    public Object getProxy(Class clz){
        //CGLIB增强类对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clz);
        //设置当前对象为代理逻辑对象
        enhancer.setCallback(this);
        //生成并返回代理对象
        return enhancer.create();
    }

    /**
     *  代理逻辑方法
     * @param proxy 代理对象
     * @param method 方法
     * @param args 参数
     * @param methodProxy 方法代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");
        //通过反射调用真实对象的方法
        Object obj = methodProxy.invokeSuper(proxy,args);
        System.out.println("调用真实对象后");
        return obj;
    }
}

六、总结

要真正的参透动态代理就要非常熟悉反射机制,从以上的代码可以得知,动态代理的底层实现还是基于反射的,我们知道反射是很消耗性能的,这带来了一些性能问题,但是为了开发上的简便,这种牺牲是值得的。我们学的框架,比如spring,mybatis等,都大量使用了动态代理技术,有兴趣的童鞋可以去阅读源码(表示本人也不是看过很多源码),这里面用到了很多的设计模式,对提高自己的代码水平很有帮助。好啦,就说到这里吧~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-08-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是代理模式
  • 二、意义
  • 三、实现动态代理的步骤
  • 四、JDK动态代理
  • 五、CGLIB动态代理
  • 六、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档