文档章节

JDK动态代理

孟飞阳
 孟飞阳
发布于 2016/08/07 12:34
字数 1303
阅读 37
收藏 0

在Spring中,严格的来说不单单使用JDK的动态代理,还会使用CGLIB动态代理,但是它们大同小异,我们这里讲JDK的动态代理,有了它的理解CGLIB也不难掌握,读者可以阅读其他的文档。

首先,让我们先了解什么是动态代理,假设读者是一个软件工程师,而你的公司是家软件公司,我是一个客户,我需要你公司提供软件的专业服务。显然我是找到你们公司的商务,而不是你去讨论我的要求。那么商务就等同于你的一个代理,我也会认为商务等于你们公司,而不会去管你这个软件工程师如何工作的。

代理的实际就是在真实服务对象(软件工程师)之前加多一个占位或者叫做代理对象(商务),这个占位(商务)可以根据调用者(客户)的要求去控制真实服务对象的访问(软件工程师)。有了这个比喻是不是好理解很多??

那么代理模式的好处在于什么?首先占位(商务)可以在真实服务对象之前之后做一些服务,同时根据需要选择是否需要启用真实服务对象,也会加入一些规则,比如商务也可以根据客户和公司的规则来提供额外的服务,这时可能就连真实服务对象(软件工程师)都不会启用。

好,上面的东西貌似很神奇,我们用一张图来表达代理的含义。

好,这里的代理对象就是我们之前谈到的占位,它代理了我们看到的真实对象,可以在真实对象之前之后,甚至是代替真实对象提供服务。

动态代理有好几种,Spring使用了CGLIG和JDK动态代理。在JDK动态代理中,要求必须提供接口,而CGLIB是不需要的,我们这里只谈论JDK动态代理,在大部分的情况下,笔者建议你使用JDK动态代理,因为JDK动态代理的速度要比CGLIB要快,在Spring中一个有切面的Bean如果有接口声明,Spring就会用JDK动态代理代理它,否者启用CGLIB。

好了论述讲了一大截,我们开始讲JDK动态代理,首先我们需要提供一个简单的接口:

public interface HelloService { 
    public void sayHello(String name);
}


跟着是实现类:

public class HelloServiceImpl implements HelloService { 
    @Override 
    public void sayHello(String name) { 
         System.err.println("hello " + name); 
    }
}

我们跟着就是要生成代理对象(proxy),分成两步: 成代理对象要建立代理对象(proxy)和真实对象(HelloServiceImpl)的代理关系。 实现代理方法 在JDK动态代理中需要实现接口:java.lang.reflect.InvocationHandler。

public class HelloProxy implements InvocationHandler { 
      private Object target; 
     /** 
       * 生成代理对象,并和真实服务对象绑定. 
       * @param target 真实服务对线下 
       * @return 代理对象 
      */ 
      public Object bind(Object target) { 
          this.target = target; //生成代理对象,并绑定. 
          Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
       //指明代理类,this代表用当前类对象,那么就要求其实现InvocationHandler接口 
        return proxy; 
       } 
     /** 
       * 当生成代理对象时,第三个指定使用HelloProxy进行代理时,代理对象调用的方法就会进入这个方法。 
       * @param proxy ——代理对象 
       * @param method -- 被调用的方法 
       * @param args -- 方法参数 
       * @return 代理方法返回。 
       * @throws Throwable -- 异常处理 
     */ 
       @Override 
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
          System.err.println("反射真实对象方法前"); 
          Object obj = method.invoke(target, args);//相当于sayHello方法调用. 
          System.err.println("反射真实对象方法后"); 
       return obj; 
    }
}

首先声明了一个类的属性,它的作用是保存真实服务对象。

然后用bind方法绑定代理对象和真实对象,是通过这样去绑定的:
 

Object proxy = Proxy.newProxyInstance(

target.getClass().getClassLoader(), //类的加载器 

target.getClass().getInterfaces(), //对象的接口,明确代理对象挂在哪些接口下 

this

);//指明代理类,this代表用当前类对象,那么就要求其实现InvocationHandler接口 

这样声明就会进入当前类invoke方法,它有三个参数:

Object proxy ——当前代理对象

Method method —— 当前调度的方法

Object[] args -- 方法参数 然后我们通过反射调度真实对象的方法,不懂的可以看到第一篇的论述(链接描述)

Object obj = method.invoke(target, args);//相当于sayHello方法调用. 让我们测试一下这段代码:

public class Chapter1Main { 
    public static void main(String[] args) { 
         HelloProxy helloProxy = new HelloProxy(); //因为使用了接口HelloService绑定了代理对象,所以可以用HelloService作为代理对象的声明. 
         HelloService proxy = (HelloService) helloProxy.bind(new HelloServiceImpl()); 
         proxy.sayHello("张三");//此时使用代理对象运行方法进入HelloProxy的invoke方法里 
  }
}

这和时候,我们运行一下可以得到下面的打印
 

反射真实对象方法前

hello 张三

反射真实对象方法后 

好了,我们看到的HelloService实际已经是一个代理对象了,而不是我们普通人看到的HelloServiceImpl这个真实对象,在Spring中不要被它迷糊了哦。
 

© 著作权归作者所有

共有 人打赏支持
孟飞阳
粉丝 206
博文 964
码字总数 543203
作品 5
朝阳
个人站长

暂无文章

线性一致性和 Raft

作者:沈泰宁 在讨论分布式系统时,共识算法(Consensus algorithm)和一致性(Consistency)通常是讨论热点,两者的联系很微妙,很容易搞混。一些常见的误解:使用了 Raft [0] 或者 paxos ...

TiDB
8分钟前
0
0
兄弟连区块链教程以太坊源码分析core-state-process源码分析

## StateTransition状态转换模型 /* The State Transitioning Model 状态转换模型 A state transition is a change made when a transaction is applied to the cu......

兄弟连区块链入门教程
10分钟前
0
0
linear-gradient渐变中的参数

在看张鑫旭的博客 遇到渐变数值后面带参数不太理解 @supports (-webkit-mask: none) or (mask: none) { .box { border: none; background: linear-gradient(to bottom, #34538...

红羊在厦门
11分钟前
0
0
Python yagmail模块自动发邮件

Python发邮件yagmail模块 import yagmail#连接服务器yag=yagmail.SMTP('xx@163.com','yy','smtp.163.com')#邮箱正文contents=["test","email send"]#发送邮件#yag.send('...

小白兔_球球
12分钟前
1
0
pada mysql

CREATE SCHEMA `exchange` DEFAULT CHARACTER SET utf8mb4 ;

qwfys
21分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部