如果想增强一个方法的功能,无非就是直接在方法体内直接修改。但这也无非给一些有代码洁癖人士一丝丝不悦!于是乎我们即不想在原来的代码里修改,又不想把原有的代码重新写一次,那么前辈们就发明了代理.
注意:本文以 JdkProxy 为基础展开所有描述!
那么一个代理过程参与的对象有以下几项:
至于为什么要用接口,这是JdkProxy的理论知识。文章结束后你也会明白!
public interface Fight {
/**
* 射击
*/
void shot();
/**
* 炸弹
*/
void bomb();
}
就是需要被代理的类!
public class BeautifulCountryTarget implements Fight {
private static final Logger LOGGER = LoggerFactory.getLogger(BeautifulCountryTarget.class);
/**
* 射击
*/
@Override
public void shot() {
LOGGER.debug("M4 shot ---> big goose!");
}
/**
* 炸弹
*/
@Override
public void bomb() {
LOGGER.debug("HIMARS fire ---> big goose!");
}
}
public class JdkProxy {
private static final Logger LOGGER = LoggerFactory.getLogger(JdkProxy.class);
/**
* 通过 Proxy.create 生成的对象是代理对象,基于 接口的代理对象,那么有以下几点是需要注意
*
* 1:生成的 代理对象 是实现了 目标接口
* 2:生成的 代理对象 与 代理目标 是兄弟关系 (都实现了同一个目标接口)
*
*/
public static void main(String[] args) throws InterruptedException {
// jdkProxy
jdkProxyTest();
}
public static void jdkProxyTest() throws InterruptedException {
//类加载器,负责把生成的class($Proxy???)文件加载到JVM
ClassLoader loader = JdkProxy.class.getClassLoader();
//需要代理的目标(对象)
BeautifulCountryTarget target = new BeautifulCountryTarget();
//增强目标方法的处理程序
InvocationHandler handler = (proxy, method, args) -> {
LOGGER.debug("大哥你在旁边看着喝Coffee!,武器开给,我来打!");
//方法调用,(目标对象,参数)
return method.invoke(target, args);
};
//创建代理人
Fight w_k_l_Fight = (Fight)Proxy.newProxyInstance(
loader,
new Class[]{Fight.class},
handler
);
//打印下类路径,方便使用 arthas 进行反张译
LOGGER.debug("proxy<w_k_l_Fight> class {}", w_k_l_Fight.getClass());
//代理人调用方法
w_k_l_Fight.shot();
w_k_l_Fight.bomb();
}
}
打印出
19:22:41.839 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- proxy<w_k_l_Fight> class class jdk.proxy1.$Proxy0
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- M4 shot ---> big goose!
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!
19:22:41.842 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- HIMARS fire ---> big goose!
可以看出代理生效了,-_-!
那么通过 Proxy.create函数生成的是一字节码文件(至于怎么生成,太高端没去研究),它被 loader 加载到JVM,通过 debug只看了类名$Proxy0
既然是系统自己生成的,那么我们自己可以自己写一个,不用系统生成的~。由理论知识可以写出以下 代理类
/**
* 模拟 通过 Proxy.create 出来的 $Proxy?? 类,
*
*/
public class SimulateProxy extends Proxy implements Fight {
protected SimulateProxy(InvocationHandler h) {
super(h);
}
/**
* 射击
*/
@Override
public void shot() {
try {
// 代理的方法
Method pMethod = Fight.class.getMethod("shot");
//调用增强处理器
super.h.invoke(this, pMethod, null);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 炸弹
*/
@Override
public void bomb() {
try {
// 代理的方法
Method pMethod = Fight.class.getMethod("bomb");
//调用增强处理器
super.h.invoke(this, pMethod, null);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public class JdkProxy {
private static final Logger LOGGER = LoggerFactory.getLogger(JdkProxy.class);
/**
* 通过 Proxy.create 生成的对象是代理对象,基于 接口的代理对象,那么有以下几点是需要注意
*
* 1:生成的 代理对象 是实现了 目标接口
* 2:生成的 代理对象 与 代理目标 是兄弟关系 (都实现了同一个目标接口)
*
*/
public static void main(String[] args) throws InterruptedException {
// 模拟代理类
simulateProxyTest();
}
public static void simulateProxyTest() {
//需要代理的目标(对象)
BeautifulCountryTarget target = new BeautifulCountryTarget();
//增强目标方法的函数
InvocationHandler handler = (proxy, method, args) -> {
LOGGER.debug("大哥你在旁边看着喝Coffee!,武器开给,我来打!");
return method.invoke(target, args);
};
//创建代理人 这里换成自己手写的
Fight w_k_l_Fight = new SimulateProxy(handler);
//代理人调用方法
w_k_l_Fight.shot();
w_k_l_Fight.bomb();
}
}
同样输出
19:38:23.950 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!
19:38:23.951 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- M4 shot ---> big goose!
19:38:23.951 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!
19:38:23.951 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- HIMARS fire ---> big goose!
我们先来看下系统生成的$Proxy0是什么样。
现在通过在main方法添加 System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");可以把系统生成的代理class文件写到目录里root/jdk/proxy1/$Proxy0.class。我这里直接贴出来,方便和上下文对比。
public final class $Proxy0 extends Proxy implements Fight {
private static final Method m0;
private static final Method m1;
private static final Method m2;
private static final Method m3;
private static final Method m4;
public $Proxy0(InvocationHandler param1) {
super(var1);
}
public final int hashCode() {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean equals(Object var1) {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void shot() {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void bomb() {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.java.coffeetime.aop.Fight").getMethod("shot");
m4 = Class.forName("com.java.coffeetime.aop.Fight").getMethod("bomb");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
private static Lookup proxyClassLookup(Lookup var0) throws IllegalAccessException {
if (var0.lookupClass() == Proxy.class && var0.hasFullPrivilegeAccess()) {
return MethodHandles.lookup();
} else {
throw new IllegalAccessException(var0.toString());
}
}
}
那么对比下系统生成的和自己手写的代理类区别 SimulateProxy和 $Proxy0,可以看出系统生成的代理类比我们手写的比较优雅一些!
equals,toString,hashCode,有意思的是代理类和目标类 equals 是 ture, 但是不同的实例!19:49:59.622 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- w_k_l_Fight equals target ? true
19:49:59.622 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- w_k_l_Fight == target ? false
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
Asitcurrentlystands,thisquestionisnotagoodfitforourQ&Aformat.Weexpectanswerstobesupportedbyfacts,references,orexpertise,butthisquestionwilllikelysolicitdebate,arguments,polling,orextendeddiscussion.Ifyoufeelthatthisquestioncanbeimprovedandpossiblyreopened,visitthehelpcenter提供指导。已关闭8年。什么是学习ruby语言
大家好,我是辣条。现在短视频可谓是一骑绝尘,吃饭的时候、休息的时候、躺在床上都在刷短视频,今天给大家带来python爬虫进阶:美拍视频地址加密解析。短视频js逆向解析抓取目标工具使用重点学习内容项目思路解析抓取目标目标网址:美拍视频工具使用开发环境:win10、python3.7开发工具:pycharm、Chrome工具包:requests、xpath、base64重点学习内容爬虫采集数据的解析过程js代码调试技巧js逆向解析代码Python代码的转换项目思路解析进入到网站的首页挑选你感兴趣的分类根据首页地址获取到进入详情页面的超链接的跳转地址找到对应加密的视频播放地址数据这个数据是静态的网页
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我刚刚发现了whatc#knowledgeshouldIhave?问题和想知道的相同,但对于Ruby。我认为Ruby是我最喜欢的编程语言,除了学习基础知识外,至少我从众多RubyonRails项目和一些Ruby脚本中学到的东西,我还尝试通过阅读像Gluttonous这样的博客来学习。,O'ReillyRuby,OlaBini,和PolishingRuby.
Unity基础知识之顶点吸附、创建组合体一、顶点吸附顶点吸附:选择物体后按住键盘上的V键,鼠标定点定位,再拖拽到目标物体对齐即可。注:操作成功后先松V键。1、两个平面Plane的顶点吸附2、两个物体cube的顶点吸附二、创建组合体(子弹)组合体子弹由2个capsule(胶囊)、1个cylinder(圆柱体)组成,如图先创建这3个对象。再将其中一个capsule按照一定比例缩小,将三个对象按照一定位置放置好。创建一个GameObject,将三个对象放在该GameObject里,这样就是父子结构。为创建的组合体即子弹可以添加材质Material:在assets目录下新建Material,选择颜色后
承接上篇文章(十分钟了解关于TCP/IP网络的基础知识)五.ARP(地址解析协议) 虽说使用IP地址确实方便了我们使用者记忆以及整理归类、寻找信息的发送目的地,但是最终接收数据的地方,还是MAC地址,于是乎,为了实现有IP地址到MAC地址的转换,引入了名为ARP(AddressResolutionProtocol)又称之为地址解析协议。 ARP通过广播(Broadcast,这是个专业名词,后面还会继续提起)的方式对LAN中所有的计算机提问:“哎,谁IP地址是10.165.7.116(上篇文章中的例子)呀?你MAC地址多少啊,快过来登记一下!”,如果有哪台计算机回复了MA
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭8年前。Improvethisquestion我是设计出身。我的编程知识是零。在学习了XHTML和CSS之后,我想学习并掌握JavaScript、jQuery等。我应该如何开始?这将是我第一次尝试编程。我可以使用和编辑现成可用的jQuery/JavaScript脚本,但我不能自己制
一、知识框架二、练习题调节一个装瓶机使其对每个瓶子的灌装量均值为μ盎司,通过观察这台装瓶机对每个瓶子的灌装量服从标准差σ=1.0盎司的正态分布。随机抽取这台机器灌装的9个瓶子组成一个样本,并测定每个瓶子的灌装量。试确定样本均值偏离总体均值不超过0.3盎司的概率。解:设每个瓶子的灌装量为X,X为样本均值,样本容量为n。由于总体X服从正态分布,样本均值X也服从正态分布,且均值相同,标准差为所以三、简述题1什么是统计量?为什么要引进统计量?统计量中为什么不含任何未知参数?答:(1)统计量的定义:设X1,X2,…,Xn是从总体X中抽取的容量为n的一个样本,如果由此样本构造一个函数T(X1,X2,…,X
本文适合有一定C#基础的初学者。设计模式含义:帮助我们降低对象之间的耦合度常用的方法称为设计模式。使用设计模式是为了可重用代码,让代码更容易被其他人所理解,保证代码可靠性,使代码编制真正工程化,这是软件工程的基石。分类:创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、组合模式、原型模式。结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。单例模式含义:一个类只有一个实例,只在内部实例一次,外部无法实例化,全局
文章目录前言一、Spring是什么?二、什么是容器?三、什么是IoC?3.1初始loC3.2举例解释loC3.3 SpringIoC思想的体现四、什么是DI?4.1DI的概念4.2 Ioc和DI的区别总结前言今天我们将进入到有关spring的认识当中,要使用它的前提就是要认识并熟悉它,上一节我们介绍了有关maven的配置,必须要配置完成后,才能完成我们后面的学习工作,让我们进入到今天的学习当中吧!!!!!!!!!一、Spring是什么?概念:我们通常所说的Spring指的是SpringFramework(Spring框架),它是⼀个开源框架,有着活跃⽽庞⼤的社区,这就是它之所以能⻓久不衰的原因