浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
- java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口、目标接口的类加载器以及InvocationHandler便可为目标接口生成代理类及代理对象。
// 方法 1: 该方法用于获取指定代理对象所关联的InvocationHandler
static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces) // 方法 3:该方法用于判断指定类是否是一个动态代理类
static boolean isProxyClass(Class cl) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的;但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。
要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。在java中如何用程序去生成一个对象的代理对象呢,java在JDK1.5之后提供了一个"java.lang.reflect.Proxy"类,通过"Proxy"类提供的一个newProxyInstance方法用来创建一个对象的代理对象,如下所示:
示例业务逻辑:
1-娱乐明星都会唱歌、演习(interface Star)
2-有一个明星叫胡歌(class HuGe implements Star)
3-他有两个助理(分别对应两个代理类)(class HuGeProxy1、class HuGeProxy2)
4-如果要找胡歌唱歌、演戏,需要先找两个助理中的一个,然后助理去找胡歌唱歌、演戏(class ProxyTest)
package com.huishe.testOfSpring.proxy; //定义一个明细接口
public interface Star { void sing(String song);//唱歌 String act(String teleplay);//表演
}
package com.huishe.testOfSpring.proxy; //创建胡歌类-实现明细接口
public class HuGe implements Star{ public void sing(String song) {
System.out.println("胡歌演唱: " + song);
} public String act(String teleplay) {
System.out.println("胡歌决定出演电视剧: " + teleplay);
return "胡歌答应出演电视剧: " + teleplay;
}
}
package com.huishe.testOfSpring.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; //胡歌代理类1
//使用一个匿名内部类来实现该接口实现InvocationHandler接口,实现invoke方法
public class HuGeProxy1 { private Star hg = new HuGe();//实例化一个对象 public Star getProcxy(){
//使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某个对象的代理对象
/**
* ClassLoader loader:Java类加载器; 可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要!
* Class<?>[] interfaces:被代理类的所有接口信息; 便于生成的代理类可以具有代理类接口中的所有方法
* InvocationHandler h:调用处理器; 调用实现了InvocationHandler 类的一个回调方法
* */
return (Star)Proxy.newProxyInstance(
getClass().getClassLoader(),
hg.getClass().getInterfaces(),
new InvocationHandler() {
/**
* InvocationHandler接口只定义了一个invoke方法,因此对于这样的接口,我们不用单独去定义一个类来实现该接口,
* 而是直接使用一个匿名内部类来实现该接口,new InvocationHandler() {}就是针对InvocationHandler接口的匿名实现类
*/
/**
* 在invoke方法编码指定返回的代理对象干的工作
* proxy : 把代理对象自己传递进来
* method:把代理对象当前调用的方法传递进来
* args:把方法参数传递进来
*
* 当调用代理对象的star.sing("逍遥叹");或者 star.act("琅琊榜")方法时,
* 实际上执行的都是invoke方法里面的代码,
* 因此我们可以在invoke方法中使用method.getName()就可以知道当前调用的是代理对象的哪个方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("sing")){
System.out.println("我是胡歌代理1,找胡歌唱歌找我");
return method.invoke(hg, args);
}
if(method.getName().equals("act")){
System.out.println("我是胡歌代理1,找胡歌演电视剧找我");
return method.invoke(hg, args);
} return null;
}
});
} }
package com.huishe.testOfSpring.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; //胡歌代理类2
//实现InvocationHandler接口,实现invoke方法
public class HuGeProxy2 implements InvocationHandler{ private Star hg = new HuGe(); public Star getProcxy(){
return (Star)Proxy.newProxyInstance(
getClass().getClassLoader(),
hg.getClass().getInterfaces(),
this);
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("sing")){
System.out.println("我是胡歌代理2,找胡歌唱歌找我");
return method.invoke(hg, args);
}
if(method.getName().equals("act")){
System.out.println("我是胡歌代理2,找胡歌演电视剧找我");
return method.invoke(hg, args);
} return null;
} }
package com.huishe.testOfSpring.proxy;
import org.junit.Test;
public class ProxyTest {
//测试代理类1
@Test
public void testHuGeProxy1(){
HuGeProxy1 proxy = new HuGeProxy1();//找到胡歌的助理
Star hg = proxy.getProcxy();//助理和胡歌洽谈
hg.sing("《逍遥叹》");//(胡歌答应后)唱歌
String actResult = hg.act("《琅琊榜》");//(胡歌答应后)演习
System.out.println("演出结果:" + actResult);
}
//测试代理类1
@Test
public void testHuGeProxy2(){
HuGeProxy2 proxy = new HuGeProxy2();
Star hg = proxy.getProcxy();
hg.sing("《逍遥叹》");
String actResult = hg.act("《琅琊榜》");
System.out.println("演出结果:" + actResult);
}
}
代理1日志输出:
我是胡歌代理1,找胡歌唱歌找我
胡歌演唱: 《逍遥叹》
我是胡歌代理1,找胡歌演电视剧找我
胡歌决定出演电视剧: 《琅琊榜》
演出结果:胡歌答应出演电视剧: 《琅琊榜》 代理2日志输出: 我是胡歌代理2,找胡歌唱歌找我
胡歌演唱: 《逍遥叹》
我是胡歌代理2,找胡歌演电视剧找我
胡歌决定出演电视剧: 《琅琊榜》
演出结果:胡歌答应出演电视剧: 《琅琊榜》
参考资料:
1-https://www.cnblogs.com/xdp-gacl/p/3971367.html
2-https://blog.csdn.net/justloveyou_/article/details/79407248
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance的更多相关文章
- 浅谈Java五大设计原则之代理模式
我们来定义一下 AOP(面向切面编程) 它是面向对象的一种补充或者是一种增强,它在这基础上增加了一些 而外的功能增强. 它可以在原有的行为不改变的前提,在这之前或者之后完成一些而外 的事情. 而AO ...
- Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)
一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...
- Java代理(静态代理、JDK动态代理、CGLIB动态代理)
Java中代理有静态代理和动态代理.静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的.静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性. J ...
- 静态代理与JDK动态代理
demo地址: https://github.com/ZbLeaning/leaning 代理: 为其他对象提供一种代理以控制对这个对象的访问.分为静态代理和动态代理.代理模式的目的就是为真实业务对象 ...
- 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式
从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...
- 代理模式详解:静态代理、JDK动态代理与Cglib动态代理
代理模式简介分类 概念 代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑. 客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代 ...
- Java中的JDK动态代理
所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...
- 017 Java中的静态代理、JDK动态代理、cglib动态代理
一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...
- Java学习笔记--JDK动态代理
1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和 ...
- Java设计模式之JDK动态代理原理
动态代理核心源码实现public Object getProxy() { //jdk 动态代理的使用方式 return Proxy.newProxyInstance( this.getClass(). ...
随机推荐
- hive理论
join操作: 这个 group by count()操作: 数据倾斜: 操作• Join on a.id=b.id• Group by• Count Distinct count(groupby)• ...
- sizeof 空类
C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1. 如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针 ...
- opencv-3.3安装记录-ubuntu 14.04
这个二逼问题不会是最后一次. ipcv-****.tar.gz 这个文件在cmake的时候会卡住,这里先下载这个文件,大概38M,放到.cache/ippcv目录下就可以了.貌似还需要改下名字. 就可 ...
- Model操作补充
参考: http://www.cnblogs.com/wupeiqi/articles/6216618.html
- ELK实时日志分析平台环境部署--完整记录(转)
在日常运维工作中,对于系统和业务日志的处理尤为重要.今天,在这里分享一下自己部署的ELK(+Redis)-开源实时日志分析平台的记录过程(仅依据本人的实际操作为例说明,如有误述,敬请指出)~ ==== ...
- Nginx缓存配置以及nginx ngx_cache_purge模块的使用
web缓存位于内容源Web服务器和客户端之间,当用户访问一个URL时,Web缓存服务器会去后端Web源服务器取回要输出的内容,然后,当下一个请求到来时,如果访问的是相同的URL,Web缓存服务器直接输 ...
- Oracle VM VirtualBox各种显示模式切换 热键
初用VirtualBox, 几个显示切换快捷键还是要记一下的: Right Ctrl + F -- 切换到全屏模式 Right Ctrl + L -- 切换到无缝模式 Ri ...
- elk日志平台搭建小记
最近抽出点时间,搭建了新版本的elk日志平台 elastaicsearch 和logstash,kibana和filebeat都是5.6版本的 中间使用redis做缓存,版本为3.2 使用的系统为ce ...
- [C语言]逆序的三位数
---------------------------------------------------------------------------------------- // main.c ...
- java程序发布成exe等
1.使用工具jartoexe http://www.regexlab.com/zh/jar2exe/free.htm http://www.jar2exe.com/ 2.exe4j.JSmooth等 ...