一、什么是代理模式

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

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

二、意义

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

三、实现动态代理的步骤

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

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

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

四、JDK动态代理

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

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

public interface HelloWorld {
void sayHello();
}

2.HelloWorld的实现类HelloWorldImpl.java

public class HelloWorldImpl implements HelloWorld {
@Override
public void sayHello() {
System.out.println("hello world");
}
}

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

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.测试

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(),需要在里面实现代理逻辑。写代码之前记得导包哦,这是第三方提供的技术。


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等,都大量使用了动态代理技术,有兴趣的童鞋可以去阅读源码(表示本人也不是看过很多源码),这里面用到了很多的设计模式,对提高自己的代码水平很有帮助。好啦,就说到这里吧~

喜欢我的小伙伴记得扫描关注呦~

java学习笔记(中级篇)—JDK动态代理的更多相关文章

  1. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring JDK动态代理

    JDK 动态代理是通过 JDK 中的 java.lang.reflect.Proxy 类实现的.下面通过具体的案例演示 JDK 动态代理的使用. 1. 创建项目 在 MyEclipse 中创建一个名称 ...

  2. java学习笔记(中级篇)—java实现高质量图片压缩

    使用java几十行代码实现一个高质量图片压缩程序,再也不用去自己找网络的压缩程序啦!而且很多网上的工具还有水印或者其他的限制,自己动手写一个简单的应用,是再合适不过了. 一.实现原理 1.声明两个字符 ...

  3. aop学习总结一------使用jdk动态代理简单实现aop功能

    aop学习总结一------使用jdk动态代理实现aop功能 动态代理:不需要为目标对象编写静态代理类,通过第三方或jdk框架动态生成代理对象的字节码 Jdk动态代理(proxy):目标对象必须实现接 ...

  4. Java反射及注解学习- 反射的使用 - JDK动态代理

    代理模式基本概念:1.代理模式的作用:为其他对象提供一种以控制对方的访问在某种情况下,一个客户不想或者不能直接引用另一个对象,代理可以在客户端和目标对象之间起到中介的作用代理的角色:(1)抽象角色:声 ...

  5. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring CGLlB动态代理

    JDK 动态代理使用起来非常简单,但是它也有一定的局限性,这是因为 JDK 动态代理必须要实现一个或多个接口,如果不希望实现接口,则可以使用 CGLIB 代理. CGLIB(Code Generati ...

  6. Java基础之反射生成JDK动态代理

    在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口.通过这个类和接口可以生成JDK动态代理类或动态代理对象. JDK动态代理例子: / ...

  7. Java学习笔记——基础篇

    Tips1:eclipse中会经常用到System.out.println方法,可以先输入syso,然后eclipse就会自动联想出这个语句了!! 学习笔记: *包.权限控制 1.包(package) ...

  8. java 学习第零篇JDK安装和记事本编辑JAVA

    用记事本来编写java 首先你要安装JDK. 第一步下载JDK. 这步不多BB. 第二部安装JDK. 你要么改安装地址或者默认. 也不多BB. 第三步配置环境变量 WIN10为例: 此电脑 右键  属 ...

  9. java学习笔记-JavaWeb篇一

    JavaWEB篇一 1 Tomcat的安装和配置 2 JavaWeb开发的目录结构 3 使用Eclipse开发JavaWeb项目 4 第一个Servlet程序 5 Servlet 的配置及生命周期方法 ...

随机推荐

  1. 走近Java之HashMap In JDK8

    HashMap,继承AbstractMap类,实现了Map接口,特性是无序不可重复,其本身的数据结构是数组加链表和红黑树.今天我们就一起来详细了解一下. 首先,需要知道,HashMap中几个关键词的含 ...

  2. python数据库-mongoDB的高级查询操作(55)

    一.MongoDB索引 为什么使用索引? 假设有一本书,你想看第六章第六节讲的是什么,你会怎么做,一般人肯定去看目录,找到这一节对应的页数,然后翻到这一页.这就是目录索引,帮助读者快速找到想要的章节. ...

  3. Python 爬虫:豆瓣电影Top250,包括电影导演、类型、年份、主演

    结果输出到文本文件中. import codecs import requests from bs4 import BeautifulSoup headers={'User-Agent': 'Mozi ...

  4. redis分布式锁的问题和解决

    分布式锁 在分布式环境中,为了保证业务数据的正常访问,防止出现重复请求的问题,会使用分布式锁来阻拦后续请求.具体伪代码如下: public void doSomething(String userId ...

  5. [Linux] Ubuntu下载jdk 和 idea

    分享一下Ubuntu如何配置JDK 并且下载Idea软件 配置JDK 1. 进入oracle:https://www.oracle.com/technetwork/java/javase/downlo ...

  6. 最大公约数GCD学习笔记

    引理 已知:k|a,k|b 求证:k|(m*a+n*b) 证明:∵ k|a ∴ 有p*k=a 同理可得q*k=b ∴ p*k*m=m*a,q*k*n=n*b ∴ k(p*m+q*n)=m*a+n*b ...

  7. [virtualenvwrapper] 命令小结

    创建环境 mkvirtualenv env1 mkvirtualenv env2 环境创建之后,会自动进入该目录,并激活该环境. 切换环境 workon env1 workon env2 列出已有环境 ...

  8. JSON的简单使用之提取多层嵌套的JSON(C#)

    JSON.NET(http://json.codeplex.com/)使用来将.NET中的对象转换为JSON字符串(序列化?),或者将JSON字符串转换为.NET中已有类型的对象(反序列化?) 反序列 ...

  9. python基础之元祖、嵌套,for循环、 enumerate、range的试用案例

    元祖又叫做只读列表,可循环查询.可切片,元祖里的直接元素不能更改,但是若里面有嵌套的列表,则可以修改列表里的元素 tu = (1,2,3,'sun',[3,4,5,'cat']) tu[4][3] = ...

  10. 通过VS2017发布.net core程序并使用Web 部署到远程服务器最新教程

    最近一个项目中,为App开发后台接口,技术选型为最新 .net core版本,使用.net core开发web api接口过程中,为了方便app团队成员直接在线调用接口,找了公网上的一台服务器做为ap ...