首页 > 最新资讯 > 正文
开班期数 开班类型 开班日期 状 态
Java班 订单班 2018-06-18 热招中
免费 试听班 2018-06-15 热招中
web班 订单班 2018-06-18 热招中
安卓 订单班 2018-06-18 热招中

咨询热线:029-89188625

学员姓名:王琨瑒

毕业学院:陕西电子科技职业技术学院

就职公司:陕西众森网络科技有限公司

薪资:8W/Y

学员姓名:井东阳

毕业学院:河北农业大学

就职公司:中软国际

薪资:10WW/Y

学员姓名:胡飞扬

毕业学院:杨凌职业技术学院

就职公司:西安美齐电子商务有限公司

薪资:8wW/Y

学员姓名:罗志敏

毕业学院:西安科技大学高新学院

就职公司:上海亲宝网

薪资:10.5W/Y

学员姓名:宿亚

毕业学院:西安科技大学高新学院

就职公司:成都旌旗数码科技有限公司

薪资:12W/Y

姓名:王琨瑒 公司:陕西众森网络科技有限公司 薪资:8W/Y

姓名:井东阳 公司:中软国际 薪资:10WW/Y

姓名:胡飞扬 公司:西安美齐电子商务有限公司 薪资:8wW/Y

姓名:罗志敏 公司:上海亲宝网 薪资:10.5W/Y

姓名:宿亚 公司:成都旌旗数码科技有限公司 薪资:12W/Y

姓名:陈明 公司:乐成网络 薪资:7.8W/Y

姓名:陈鑫 公司:北京易道用车 薪资:10.4W/Y

姓名:段大志 公司:翔傲信息科技有限公司 薪资:10.5W/Y

姓名:牛鹏 公司:陕西广电网络公司 薪资:9.7W/Y

姓名:范鑫 公司:天网软件股份有限公司 薪资:12.6W/Y

姓名:常亚东 公司:西安宝亿电子科技有限公司 薪资:9.8W/Y

姓名:杨闯 公司:翔傲信息科技有限公司 薪资:11.6W/Y

姓名:管喆 公司:翔傲信息科技有限公司 薪资:9.8W/Y

姓名:杨胜 公司:西安和利德软件有限公司 薪资:11W/Y

姓名:魏康 公司:西安天讯网络技术有限公司 薪资:13.6W/Y

姓名:马延国 公司:深圳市海博软件有限公司 薪资:9.6W/Y

姓名:党洁 公司:北京金山网络 薪资:13W/Y

姓名:王志军 公司:西安和利德软件有限公司 薪资:12W/Y

姓名:武曌罡 公司:翔傲信息科技有限公司 薪资:11W/Y

姓名:侯增伟 公司:翔傲信息科技有限公司 薪资:10W/Y

首页 > 最新资讯 > 正文

Java基础知识,说说Java代理模式

Java基础知识,说说Java代理模式
西安it培训平时写代码时,经常会用到各种设计模式,其中一种就是代理模式,代理实现可以分为静态代理和动态代理。

静态代理

静态代理的模式在平时生活中也很常见,比如买火车票这件小事,黄牛相当于是火车站的代理,我们可以通过黄牛或者代售点进行买票行为,但只能去火车站进行改签和退票,因为只有火车站才有改签和退票的方法。

在代码实现中相当于为一个委托对象realSubject提供一个代理对象proxy,通过proxy可以调用realSubject的部分功能(买票),并添加一些额外的业务处理(收取手续费),同时可以屏蔽realSubject中未开放的接口(改签和退票)。

Java基础知识,说说Java代理模式

 

1、RealSubject 是委托类,Proxy 是代理类;

2、Subject 是委托类和代理类的接口;

3、request() 是委托类和代理类的共同方法;

4、RealSubject 中有未公开的方法

具体代码实现如下:

interface Subject {
 void request();
}
class RealSubject implements Subject {
 public void request(){
 System.out.println("RealSubject");
 }
}
class Proxy implements Subject {
 private Subject subject;
 
 public Proxy(Subject subject){
 this.subject = subject;
 }
 public void request(){
 System.out.println("begin");
 subject.request();
 System.out.println("end");
 }
}
public class ProxyTest {
 public static void main(String args[]) {
 RealSubject subject = new RealSubject();
 Proxy p = new Proxy(subject);
 p.request();
 }
}

静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。

动态代理

动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,动态代理分为jdk动态代理和cglib动态代理,下面通过一个例子看看如何实现jdk动态代理。

1、定义业务逻辑

public interface Service { 
 //目标方法 
 public abstract void add(); 
} 
public class UserServiceImpl implements Service { 
 public void add() { 
 System.out.println("This is add service"); 
 } 
} 

2、利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。

class MyInvocatioHandler implements InvocationHandler {
 private Object target;
 public MyInvocatioHandler(Object target) {
 this.target = target;
 }
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 System.out.println("-----before-----");
 Object result = method.invoke(target, args);
 System.out.println("-----end-----");
 return result;
 }
 // 生成代理对象
 public Object getProxy() {
 ClassLoader loader = Thread.currentThread().getContextClassLoader();
 Class<?>[] interfaces = target.getClass().getInterfaces();
 return Proxy.newProxyInstance(loader, interfaces, this);
 }
}

3、使用动态代理

public class ProxyTest {
 public static void main(String[] args) {
 Service service = new UserServiceImpl();
 MyInvocatioHandler handler = new MyInvocatioHandler(service);
 Service serviceProxy = (Service)handler.getProxy();
 serviceProxy.add();
 }
}

执行结果:

-----before-----
This is add service
-----end-----

代理对象的生成过程由Proxy类的newProxyInstance方法实现,分为3个步骤:

1、ProxyGenerator.generateProxyClass方法负责生成代理类的字节码,生成逻辑比较复杂,有兴趣的同学可以继续分析源码 sun.misc.ProxyGenerator;

// proxyName:格式如 "com.sun.proxy.$Proxy.1";
// interfaces:代理类需要实现的接口数组;
// accessFlags:代理类的访问标识;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

2、native方法Proxy.defineClass0负责字节码加载的实现,并返回对应的Class对象。

Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);

3、利用clazz.newInstance反射机制生成代理类的对象;

反编译代理类

为了更清楚的理解动态代理,通过以下方式把代理类字节码生成class文件。

byte[] classFile = ProxyGenerator.generateProxyClass("com.sun.proxy.$Proxy.1", service.getClass().getInterfaces());
FileOutputStream out = new FileOutputStream("com.sun.proxy.$Proxy.1.class");
out.write(classFile);
out.flush();

使用 反编译工具 jad jad com.sun.proxy.$Proxy.1 看看代理类如何实现,反编译出来的java代码如下:

public final class $proxy1 extends Proxy implements Service {
 public $proxy1(InvocationHandler invocationhandler) {
 super(invocationhandler);
 }
 public final boolean equals(Object obj) {
 try {
 return ((Boolean)super.h.invoke(this, m1, new Object[] {
 obj
 })).booleanValue();
 }
 catch(Error _ex) { }
 catch(Throwable throwable) {
 throw new UndeclaredThrowableException(throwable);
 }
 }
 public final String toString() {
 try {
 return (String)super.h.invoke(this, m2, null);
 }
 catch(Error _ex) { }
 catch(Throwable throwable) {
 throw new UndeclaredThrowableException(throwable);
 }
 }
 public final void add() {
 try {
 super.h.invoke(this, m3, null);
 return;
 }
 catch(Error _ex) { }
 catch(Throwable throwable) {
 throw new UndeclaredThrowableException(throwable);
 }
 }
 public final int hashCode() {
 try {
 return ((Integer)super.h.invoke(this, m0, null)).intValue();
 }
 catch(Error _ex) { }
 catch(Throwable throwable) {
 throw new UndeclaredThrowableException(throwable);
 }
 }
 private static Method m1;
 private static Method m2;
 private static Method m3;
 private static Method m0;
 static {
 try {
 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
 Class.forName("java.lang.Object")
 });
 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 m3 = Class.forName("zzzzzz.Service").getMethod("add", new Class[0]);
 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
 }
 catch(NoSuchMethodException nosuchmethodexception) {
 throw new NoSuchMethodError(nosuchmethodexception.getMessage());
 }
 catch(ClassNotFoundException classnotfoundexception) {
 throw new NoClassDefFoundError(classnotfoundexception.getMessage());
 }
 }
}

从上述代码可以发现:

1、生成的$proxy1继承自Proxy类,并实现了Service接口。

2、执行代理对象的方法,其实就是执行InvocationHandle对象的invoke方法,传入的参数分别是当前代理对象,当前执行的方法和参数。

super.h.invoke(this, m3, null);

JDK动态代理局限性

通过反射类Proxy和InvocationHandler回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。

 

  • 特马开奖结果查询201
  • 今晚特马号开什么
  • 王中王铁箄盘开奖结果免费
  • 特马生肖号码
  • 重特难防今期开打一肖, 香港九龙心水高手论坛?
  • 小玄机王(信封), 黑庄克星一肖一码彩图
  • 管家四不像图20期
  • 香港四字玄机, 香港网址金多宝论坛
  • 77111小兔子, 2019年香港看今晚开奖结果
  • 另版香港六合皇-A, 2019最准生肖诗
  • 江南公式网, 香港平码三中三资料
  • 2019年白姐先锋诗
  • 东方心经-(合), 1396香港免费公开资料
  • 千金点特A, 香港官方网资料
  • 王中王手机论坛免费
  • 120期正板四不像生肖必出一肖图, 葡京赌侠诗2015全年资料
  • 管家婆王中王论坛资料一肖中特
  • 彩吧上错杀肖统计, 百晓生高手论坛
  • 神算子论坛必中三码139, 个人心水资料免费发放
  • 三期之内定开生肖
  • 优雅原创手写正版资料, 护民图库上最早大全集
  • 2019年神童输尽光115期, 十二生肖表
  • 梦特轩, 2017年生肖歇后语大全
  • 管家四不像图
  • 西科软件网站logo

    中华人民共和国工信部、通信管理局备案号:陕ICP备14010485号-1 备案查询 管理

    西科软件:陕西省西安市高新区科技路37号海星城市广场B座2102

    全国免费咨询热线:029-89188625

    乘车路线:14路、211路、218路、219路、220路、226路、308路、604路、608路到亚美大厦站

    长安校区:西安子午大道中段39号西安科技大学高新学院北校区

    乘车路线:4-14路、322路、游9路、320路到下北良村站下车