一、代理概念

   代理在我们日常生活经常听到这个名词,比如我们想看下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. String类的源码分析

    之前面试的时候被问到有没有看过String类的源码,楼主当时就慌了,回来赶紧补一课. 1.构造器(构造方法) String类提供了很多不同的构造器,分别对应了不同的字符串初始化方法,此处从源码中摘录如 ...

  2. MapReduce极简教程

    一个有趣的例子 你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查并且数出有多少张是黑桃?   MapReduce方法则是: 给在座的所有玩家中分配这摞牌 让每个玩家数自己手中的牌有几张是黑桃,然后 ...

  3. 【转】开源中国上看到的一个vim的自动配置的好东西,分享下

    https://www.oschina.net/p/onekey-to-vim-ide 变量有高亮,竖行上有直线定位,对python的支持效果更佳,从事C/C++开发的程序员使用也不错.

  4. 21.Linux-写USB键盘驱动(详解)

    本节目的: 根据上节写的USB鼠标驱动,来依葫芦画瓢写出键盘驱动 1.首先我们通过上节的代码中修改,来打印下键盘驱动的数据到底是怎样的 先来回忆下,我们之前写的鼠标驱动的id_table是这样: 所以 ...

  5. 即时通信系统Openfire分析之五:会话管理

    什么是会话? A拨了B的电话 电话接通 A问道:Are you OK? B回复:I have a bug! A挂了电话 这整个过程就是会话. 会话(Session)是一个客户与服务器之间的不中断的请求 ...

  6. VNC实现Windows远程访问Ubuntu 16.04(无需安装第三方桌面)

    本文主要是讲解如果理由VNC实现Windows远程访问Ubuntu 16.04,其实网上有很多类似教程,但是很多需要安装第三方桌面(xfce桌面等等),而且很多人不太喜欢安装第三方桌面,很多人像笔者一 ...

  7. #云栖大会# 移动安全专场——APP加固新方向(演讲速记)

    主持人导语: 近些年来,移动APP数量呈现爆炸式的增长,黑产也从原来的PC端转移到了移动端,伴随而来的逆向攻击手段也越来越高明.在解决加固产品容易被脱壳的方案中,代码混淆技术是对抗逆向攻击最有效的方式 ...

  8. sqlDependency监控数据库数据变化,自动通知

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. word遇到错误 使其无法正常工作 因此需要关闭word 是否希望我们立刻修复

    方法1: 网上找的方案: win10下按下快捷键win+R, 然后在里面输入 %appdata%\microsoft\templates ,确定,此时就会直接进入Word安装路径,在里面找到" ...

  10. 面向对象(OOP)--OOP基础与this指向详解

      前  言            学过程序语言的都知道,我们的程序语言进化是从“面向机器”.到“面向过程”.再到“面向对象”一步步的发展而来.类似于汇编语言这样的面向机器的语言,随着时代的发展已经逐 ...