动态代理及java演示
代理模式的理解
- 直观的,可以避免调用方和被调用的对象产生直接的联系。也就是程序设计中耦合度问题。
- 其次,通过代理可以实现目标对象本身所不具备的行为功能。比如明星只负责演出,而经纪人则负责安排档期、经费、缴税等工作。
- 目标对象:车主、明星
- 代理人:黄牛、经纪人
- 行为:办审核手续、唱歌跳舞
- 提出方、调用方:警察、商人
说回到程序中,代理主要有以下两种形式:
代理的形式之一:静态代理
public interface IStar {
void SingAsong(String songName);
}
public class Star implements IStar {
private String _name;
public Star(String name) {
this._name = name;
}
@Override
public void SingAsong(String songName) {
System.out.println("i am " + _name + ",I'm singing....");
}
}
public class StaticStarProxy implements IStar {
Star zhangsanStar = new Star("zhangsan");
@Override
public void SingAsong(String songName) {
this.PlanSingDate();
zhangsanStar.SingAsong(songName);
this.PayingTax();
}
private String PlanSingDate() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.MONTH, 2);
Date singDate = calendar.getTime();
System.out.println("sing date =" + singDate);
return singDate.toString();
}
private void PayingTax() {
System.out.println("payint tex....");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("starting....");
//直接调用,直接与明星对线
IStar zhangsanStar = new Star("zhangsan");
zhangsanStar.SingAsong("molihua");
System.out.println();
System.out.println("stoping");
}
- 如果采用多个明星对应多个代理类的话,那么就会产生大量的代理类出现。【虽然在现实生活中是合理的,但是程序中一般追求精简】
- 如果采用多个明星对应一个代理类,那么这个代理类的实现就会很复杂,且代理类变更频繁。
- 还有一个问题,如果明星增加技能(比如跳舞),那么代理类就需要同步的变更。
代理的形式之二:动态代理
public class DnyamicStarProxy implements InvocationHandler {
IStar _targetStar;
public DnyamicStarProxy(IStar star) {
this._targetStar = star;
}
@Override
public Object invoke(Object proxyInstance, Method method, Object[] objects) throws Throwable {
this.PlanSingDate();
Object invokeResult = method.invoke(_targetStar, objects);
this.PayingTax();
return invokeResult;
}
private String PlanSingDate() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.MONTH, 2);
Date singDate = calendar.getTime();
System.out.println("sign date =" + singDate);
return singDate.toString();
}
private void PayingTax() {
System.out.println("the agent is paying tex....");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("starting....");
//直接调用,直接与明星对线
IStar zhangsanStar = new Star("zhangsan");
zhangsanStar.SingAsong("molihua");
System.out.println();
//代理模式,通过经纪人对线
IStar zhangsanProxy = (IStar) new StaticStarProxy();
zhangsanProxy.SingAsong("molihua");
System.out.println();
//代理模式,动态代理调用
System.out.println("邀请李四演出:");
IStar lisiStar = new Star("lisi");
IStar lisiStarProxy = (IStar) Proxy.newProxyInstance(IStar.class.getClassLoader()
, new Class[]{IStar.class}
, new DnyamicStarProxy(lisiStar));
lisiStarProxy.SingAsong("molihua");
System.out.println();
System.out.println("邀请王五演出:");
IStar wangwuStar = new Star("wangwu");
IStar wangwuStarProxy = (IStar) Proxy.newProxyInstance(IStar.class.getClassLoader()
, new Class[]{IStar.class}
, new DnyamicStarProxy(wangwuStar));
wangwuStarProxy.SingAsong("molihua");
System.out.println();
System.out.println("stoping");
}
starting....
i am zhangsan,I'm singing....
sing date =Wed Mar 16 18:14:17 CST 2022
i am zhangsan,I'm singing....
payint tex....
邀请李四演出:
sign date =Wed Mar 16 18:14:17 CST 2022
i am lisi,I'm singing....
the agent is paying tex....
邀请王五演出:
sign date =Wed Mar 16 18:14:17 CST 2022
i am wangwu,I'm singing....
the agent is paying tex....
stoping
进程已结束,退出代码为 0
- 入参o代表:动态生成的代理类对象
- 入参method代表;调用方调用的哪个方法,演示代码中即代表SingAsong方法
- 入参objects代表:调用方法传入的参数,即实参
- 参数loader:代表java反射中的类加载器
- 参数interfaces:代表依赖的接口
- 参数h:代表动态代理类的的对象,即DnyamicStarProxy
- 只有一个DnyamicStarProxy类,而省掉了具体的各个代理人的类;
- 对商人(调用方)来说,只需要提前知道想要邀请的明星(李四、王五),然后通过特定的代码就生成了明星经纪人对象(lisiStarProxy、wangwuStarProxy)
- 得到经纪人对象后,就可以通过经纪人对象调用执行具体的行为(唱歌)。
- 目标对象:Star,没有额外的变化
- 代理人:省掉了具体的xxx代理人,转为DnyamicStarProxy类,从而依赖InvocationHandler类。
- 行为:IStar,没有额外的变化
- 调用方:依赖IStar接口、特定的Star类对象、Proxy类、DnyamicStarProxy类
动态代理的一些常见思考题:
※Java常用的动态代理技术有哪些?
本次演示程序虽然用到反射技术来实现动态代理,但也有其它技术来实现比如CGLIB等
※演示代码中,调用方还是new了具体的明星类(lisiStar、wangwutar),这就产生了严重的依赖。有什么办法可以解除这个依赖?
※DnyamicStarProxy.Invoke中通过反射执行了目标对象的方法(Star.SingAsong),此时执行的代码是本地的代码。如果这里通过socket将方法名、入参发送到另一台server上执行,然后把结果在再通过网络返回,这就是RPC框架中常用的动态代理了。
※虽然是动态代理,但根据前面的铺垫,按说也是会生成代理类的吧,那动态生成的代理长什么样?
注意动态代理类的SingAsong方法;
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import Stars.IStar;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class DynamicGeneratedStarProxyClass extends Proxy implements IStar {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public DynamicGeneratedStarProxyClass(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void SingAsong(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
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 int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("Stars.IStar").getMethod("SingAsong", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
动态代理及java演示的更多相关文章
- 动态代理:JDK原生动态代理(Java Proxy)和CGLIB动态代理原理+附静态态代理
本文只是对原文的梳理总结,以及自行理解.自己总结的比较简单,而且不深入,不如直接看原文.不过自己梳理一遍更有助于理解. 详细可参考原文:http://www.cnblogs.com/Carpenter ...
- 实现动态代理(Java和spring)
一.Java实现动态代理 1.创建接口 package com.oyy.mw.biz.i; public interface Cal { public int add(int num1,int num ...
- 设计模式之动态代理(Java的JDK动态代理实现)
先来看一下思维导图: 对于JDK的动态代理,孔浩老师说学习的方法是把它记下来. 先写一个主题接口类,表示要完成的一个主题. package com.liwei.dynaproxy; /** * 要代理 ...
- Java JDK 动态代理使用及实现原理分析
转载:http://blog.csdn.net/jiankunking 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...
- Java动态代理深入解析
要想了解Java动态代理,首先要了解什么叫做代理,熟悉设计模式的朋友一定知道在Gof总结的23种设计模式中,有一种叫做代理(Proxy)的对象结构型模式,动态代理中的代理,指的就是这种设计模式. 在我 ...
- Java编程的逻辑 (86) - 动态代理
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- java动态代理_aop2
一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模 ...
- Java基础加强-(注解,动态代理,类加载器,servlet3.0新特性)
1. Annotation注解 1.1. Annotation概述 Annotation是JDK 5.0以后提供对元数据的支持,可以在编译.加载和运行时被读取,并执行相应的处理.所谓Annota ...
- Java动态代理——框架中的应用场景和基本原理
前言 之前已经用了5篇文章完整解释了java动态代理的原理,本文将会为这个系列补上最后一块拼图,展示java动态代理的使用方式和应用场景 主要分为以下4个部分 1.为什么要使用java动态代理 2.如 ...
随机推荐
- 当页面是本地页面时,通过ajax访问tomcat里的action,传递的参数在action里并不能识别
当页面是本地页面时,通过ajax访问tomcat里的action,传递的参数在action里并不能识别,这个问题困扰了我不少时间. 在测试时发现此问题
- Uni-app原生插件入门使用教程-[1]从Uni-app插件市场试用插件
[1]从Uniapp插件市场试用插件 当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力. 如使 ...
- 【论文笔记】 Popularity Bias in Dynamic Recommendation
Popularity Bias in Dynamic Recommendation Authors: Ziwei Zhu, Yun He, Xing Zhao, James Caverlee KDD' ...
- 人工智能论文解读精选 | PRGC:一种新的联合关系抽取模型
NLP论文解读 原创•作者 | 小欣 论文标题:PRGC: Potential Relation and Global Correspondence Based Joint Relational ...
- c++11之all_of 、 any_of 和 none_of 的用法
0.时刻提醒自己 Note: vector的释放 1.区别 函数 功能 all_of 区间[开始, 结束)中是否所有的元素都满足判断式p,所有的元素都满足条件返回true,否则返回false. any ...
- 【LeetCode】399. Evaluate Division 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- Harry Potter and the Hide Story(hdu3988)
Harry Potter and the Hide Story Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 ...
- codeforce-601A. The Two Routes(最短路)
题意: 给你N个点表示N个站,有汽车和火车,汽车只能走公路,火车只能走铁路. 然后给你M条双向路,代表这两个点之间有铁路连接. 然后告诉你如果两个点之间没有铁路,那么就是公路连接. 问你汽车和火车都到 ...
- 1319 - Monkey Tradition
1319 - Monkey Tradition PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB ...
- Redis 的 3 种集群方案对比
数据持久化 主从复制 自动故障恢复 集群化 数据持久化本质上是为了做数据备份,有了数据持久化,当Redis宕机时,我们可以把数据从磁盘上恢复回来,但在数据恢复之前,服务是不可用的,而且数据恢复的时间取 ...