一、代理概念

   代理在我们日常生活经常听到这个名词,比如我们想看下google我们需要找个代理服务器来帮我们一下,比如我们想买一个外国的什么东西需要在代购网站或者找朋友帮忙在外国买一下,用概念一点话来说就是通过代理对象来间接访问目标对象,这里代理对象就是我们上面代理服务器和代购网站,目标对象就是你要实现的目的;明白什么是代理我们来说下我们今天重点,代理的两种模式静态代理和动态代理,这个是怎么区别的我们谈一下,Java中都是通过编译器生成.class文件,在通过JVM读取,然后加载到内存中,生成对应的需要对象,根据代理类创建的时间分成静态和动态代理,静态的代理就是在程序运行前.class文件就存在,我们经常使用的代理模式就是静态代理,动态代理就是程序运行时动态创建,比如JDK的动态代理和CGLB代理;下面我们就针对这几种情况来详细说一下;

二、静态代理----代理模式

   这里我们使用取款机这个例子来说一下,现在假如说你是招商的银行卡,你需要在工商取款机取款,这里有个规定那就是每笔需要收费2元,这个工商取款机就是代理对象,你的目标对象就是取款,我们抽象一个取款的接口WithdrawService,招商取款机上面的实现取款机接口ATM,然后工商取款机ATMProxy实现代理角色;当然这里我简化很多步骤;

/**
* Created by wangt on 2017/11/2.
* 抽象的取款接口
*/
public interface WithdrawService {
int GetByMoneyWithdraw(int money);
} /**
* Created by wangt on 2017/11/2.
* ATM机实现的接口
*/
public class ATM implements WithdrawService{
@Override
public int GetByMoneyWithdraw(int money) {
System.out.print("取款"+money);
return money;
}
} /**
* Created by wangt on 2017/11/2.
* 代理对象
*/
public class ATMProxy implements WithdrawService {
private ATM atm;
public ATMProxy(ATM atm){
this.atm=atm;
}
@Override
public int GetByMoneyWithdraw(int money) { int proxyMoney=2;
System.out.print("取款"+money+":"+"手续费"+proxyMoney);
atm.GetByMoneyWithdraw(money+proxyMoney);
return money+proxyMoney;
}
}
/**
* Created by wangt on 2017/11/2.
* 测试类
*/
public class ProxyTest {
public static void main(String[] args){
WithdrawService withdrawService=new ATMProxy(new ATM());
withdrawService.GetByMoneyWithdraw(1000);
}
}

以上就是静态代理,在运行前就生成,代理模式的优点就在于不直接依赖于目标对象,而是通过代理对象作为中间对象也就是我们经常说的解耦;另外代理对象还可以对实现的方法进行增强,增加自己的规则,这里我们思考一个问题:当我们每增加一个代理类的时候,我就需要编写一个类,这样我们代码通用很差,另外这样子会照成系统更加复杂,执行速度更加慢;这就背离了我们设计的原则,那么怎么避免这种问题尼?

三、动态代理----JDK动态代理

针对于上面提出的问题,通过反射机制,JDK给我们提供Proxy类,这个只是针对于接口的增强,在JVM运行时动态创建生成。这里简单说一下JDK通过接口动态生成代理对象的过程:

1.获取WithdrawService接口下所有方法;

2.生成代理类,默认为命名空间+$+Proxy+类名;

3.根据接口,在代码中动态创建代理的字节码文件;

4.将字节码文件转化为class文件;

5.创建InvocationHandler实例handler,来处理代理的方法调用

6.Proxy的class对象以创建的handler对象为参数,实例一个proxy对象;

下面我们展示一下JDK实现代理:

/**
* Created by wangt on 2017/11/2.
* 抽象的取款接口
*/
public interface WithdrawService {
int GetByMoneyWithdraw(int money);
} /**
* Created by wangt on 2017/11/2.
* ATM机实现的接口
*/
public class ATM implements WithdrawService{
@Override
public int GetByMoneyWithdraw(int money) {
System.out.print("取款"+money);
return money;
}
} /**
* Created by wangt on 2017/11/3.
* JDK动态代理的实现
*/
public class ATMJDKProxy implements InvocationHandler {
//目标对象
private Object target;
//构建目标对象
public ATMJDKProxy(Object target){
super();
this.target=target;
}
//获取目标的代理对象
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),this.target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("执行前处理什么事情");
Object result = method.invoke(target, args);
System.out.print("执行后处理什么事情");
return result;
}
} /**
* Created by wangt on 2017/11/2.
* 测试类
*/
public class ProxyTest { public static void main(String[] args) {
WithdrawService withdrawService=new ATM();
ATMJDKProxy atmjdkProxy=new ATMJDKProxy(withdrawService);
WithdrawService proy= (WithdrawService) atmjdkProxy.getProxy();
proy.GetByMoneyWithdraw(1000);
}
}

四、动态代理----CGLIB动态代理

JDK动态代理只能实现对接口方法的增强,不能实现对接口类的的动态代理。那么我们想动态生成类的时候怎么办,不用想了那就是使用CGLIB类库;这个当然也是在JVM运行时动态创建,这里也简单描述下生成ATM动态代理类的过程:

1.查找ATM类中的非final的public类型方法;

2.将这些方法定义转化为字节码;

3.将组成字节码转化为代理的Clss类;

4.实现MethodInterceptor 接口,用来处理代理方法上的请求;

下面我们展示一下CGLIB实现代理:

/**
* Created by wangt on 2017/11/2.
* ATM不实现接口
*/
public class ATM {
public int GetByMoneyWithdraw(int money) {
System.out.print("取款"+money);
return money;
}
} /**
* Created by wangt on 2017/11/3.
* 实现MethodInterceptor
*/
public class ATMCGLIBProxy implements MethodInterceptor {
private Object target;
public Object getInstance(Object target){
this.target=target;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始前");
methodProxy.invokeSuper(o,objects);
System.out.println("开始后");
return null;
}
}
/**
* Created by wangt on 2017/11/2.
* 测试类
*/
public class ProxyTest { public static void main(String[] args) {
ATMCGLIBProxy cglib=new ATMCGLIBProxy();
ATM atm = (ATM) cglib.getInstance(new ATM());
atm.GetByMoneyWithdraw(1000);
}
}

以上是基本实现,这里我们简单说一下CGLIB底层是通过使用字节码处理框架ASM,来转换字节码并生成新的类;什么是ASM?ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

这里需要注意使用这个的时候需要引入:cglib-nodep-2.2.jar;cglib-2.2.jar;asm-3.2jar;

 五、动态代理----应用场景

  大家执行过上面的代码以后会有一种是曾相识的感觉,在方法执行前做一些事,在方法执行后做一些事,使我们很容易想到Spring Aop中的通知,这里确实有用到动态代理,至于别的我暂时还没有想到,等等那天解读Spring源码的时候我们再来探讨一下,到此结束;

 六、一些感悟

  扎实基础!!扎实基础!!扎实基层!!JDK源码还是需要读,马上开始深入学习Java虚拟机了,我也会分享一些学习的经验,加油!!可以加入我的群大家一起学习:438836709,我会经常发一些鸡汤或者学习资料给大家!一起进步!!如果想交流C#也可以!!另外ASM大家可以放一放!

Java--谈一谈代理的更多相关文章

  1. JAVA基础细谈

    JAVA基础细谈 一. 源文件和编译后的类文件     源文件的本质就是程序文件,是程序员编写,是人看的.而编译后的类文件是给电脑看的文件.一个类就是一个文件,无论这个类写在哪里,编译以后都是一个文件 ...

  2. java设计模式之Proxy(代理模式)

    java设计模式之Proxy(代理模式) 2008-03-25 20:30 227人阅读 评论(0) 收藏 举报 设计模式javaauthorizationpermissionsstringclass ...

  3. 杨晓峰-Java核心技术-6 动态代理 反射 MD

    目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...

  4. 谈一谈Java8的函数式编程(二) --Java8中的流

    流与集合    众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...

  5. 从一张图开始,谈一谈.NET Core和前后端技术的演进之路

    从一张图开始,谈一谈.NET Core和前后端技术的演进之路 邹溪源,李文强,来自长沙.NET技术社区 一张图 2019年3月10日,在长沙.NET 技术社区组织的技术沙龙<.NET Core和 ...

  6. 蓝的成长记——追逐DBA(5):不谈技术谈业务,恼人的应用系统

    ***************************************声明*************************************** 个人在oracle路上的成长记录,当中 ...

  7. 自己写一个java.lang.reflect.Proxy代理的实现

    前言 Java设计模式9:代理模式一文中,讲到了动态代理,动态代理里面用到了一个类就是java.lang.reflect.Proxy,这个类是根据代理内容为传入的接口生成代理用的.本文就自己写一个Pr ...

  8. 使用Java中的动态代理实现数据库连接池

    2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...

  9. java 笔记(3) —— 动态代理,静态代理,cglib代理

    0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...

  10. java中的动态代理机制

    java中的动态代理机制 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现 ...

随机推荐

  1. Struts访问的时候出现request=null的情况

    今天用Struts框架写个小应用的时候,出现了如下问题 private File upload;    private String uploadContentType;    private Str ...

  2. ArcGIS连带文字注记导出为CAD格式

    可以使用ArcGIS的"Export To CAD"工具将点.线.面等要素直接导出为CAD格式.如果要连带将ArcGIS中的文字标注导出为CAD格式要稍麻烦一点,下面是一个例子. ...

  3. 多年iOS开发经验总结

    总结了几个月的东西终于能和大家分享了,不多说,直接看东西! 1.禁止手机睡眠 1 [UIApplication sharedApplication].idleTimerDisabled = YES; ...

  4. JSP 入门

    request是请求,即客服端发来的请求. response是响应,是服务器做出的响应 redirect页面重定向 forward页面跳转 不改变url 四个作用域 如果把变量放到pageContex ...

  5. hdu1512 Monkey King(左偏树 + 并查集)

    Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its o ...

  6. 苹果iPhone X上搭载的那颗A11仿生芯片,到底牛在哪?

    苹果iPhone X上搭载的那颗A11仿生芯片,到底牛在哪? 上周,苹果公司在刚刚落成投入使用的“飞船”新总部(Apple Park)举行2017年秋季新品发布会,整场发布会基本被iPhone X抢尽 ...

  7. “一切都是消息”--MSF(消息服务框架)之【发布-订阅】模式

    在上一篇,“一切都是消息”--MSF(消息服务框架)之[请求-响应]模式 ,我们演示了MSF实现简单的请求-响应模式的示例,今天来看看如何实现[发布-订阅]模式.简单来说,该模式的工作过程是: 客户端 ...

  8. 前端要革命?看我在js里写SQL

    在日新月异的前端领域中,前端工程师能做的事情越来越多,自从nodejs出现后,前端越来越有革了传统后端命的趋势,本文就再补一刀,详细解读如何在js代码中执行标准的SQL语句 为什么要在js里写SQL? ...

  9. 部署LAMP+NFS实现双Web服务器负载均衡

    一.需求分析 1.前端需支持更大的访问量,单台Web服务器已无法满足需求了,则需扩容Web服务器: 2.虽然动态内容可交由后端的PHP服务器执行,但静态页面还需要Web服务器自己解析,那是否意味着多台 ...

  10. win8.1 安装

    下载了Windows8.1企业版的iso文件,文件名称:cn_windows_8_1_enterprise_x86_dvd_2791409.iso 下载地址: http://msdn.itellyou ...