热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

利用代码分别实现jdk动态代理和cglib动态代理_代理模式

代理模式分为静态代理和动态代理,其中动态代理又分为JDK动态代理和CGLIB动态代理代理模式的三个要素:A、抽象的类或者接口——完成一件怎样的事情B、被
97911c01022e91cf2c4702fa3dc92ebe.png

代理模式分为静态代理动态代理,其中动态代理又分为JDK动态代理CGLIB动态代理

代理模式的三个要素:

A、抽象的类或者接口 —— 完成一件怎样的事情

B、被代理对象 —— 事情操作具体内容

C、代理对象 —— 帮助我们完成事情的同时还可以增加其他的功能

为了便于理解写了个具体的例子: 我们找中介租房子

A、抽象的类或者接口 —— 租房子

B、被代理对象 —— 房东

C、代理对象 —— 中介

代理模式的好处:

A、房东可以安心的做自己的事情 —— (被代理对象可以做自己的事情,不会被其他代码所干扰)

B、我们有了问题直接找中介 —— (被代理对象变得比较安全)

C、可以增强代码的扩展性


静态代理

静态代理实现代码:

1、定义抽象的类或者接口 —— 定义我们需要完成租房的事情

package com.bj.proxy1;
/** 抽象的类或者接口* 定义我们需要完成租房的事情*/
public interface LetRoom {public void zf();
}

2、定义被代理对象 —— 房东

package com.bj.proxy1;/** 被代理对象 —— 房东1*/
public class Landlord implements LetRoom{@Overridepublic void zf() {System.out.println("--出租国际大厦1号楼4层406--");}}package com.bj.proxy1;/** 被代理对象 —— 房东2*/
public class Landlord2 implements LetRoom{@Overridepublic void zf() {System.out.println("--出租国际大厦2号楼5层505--");}}

3、定义代理对象 —— 中介

package com.bj.proxy1;/** 代理对象 —— 中介*/
public class Intermediary implements LetRoom{private int money;public Intermediary(int money) {this.money &#61; money;}&#64;Overridepublic void zf() {System.out.println("--收取推荐费50元--");//出租房东的租房——中介调用的租房方法仍然是房东的租房方法if(money <&#61;800 ) {Landlord landlord &#61; new Landlord();landlord.zf();}else if(money <2000 && money >800) {Landlord2 landlord2 &#61; new Landlord2();landlord2.zf();}System.out.println("--收取管理费100元--");}}

4、我们的租房操作

package com.bj.proxy1;//我们的租房操作
public class MyRentRoom {public static void main(String[] args) {Intermediary intermediary &#61; new Intermediary(1000);intermediary.zf();}
}

804da1337dd6b1bd9edec50e12c4c8a0.png
运行结果

现在可以看到&#xff0c;代理模式可以在不修改被代理对象的基础上&#xff0c;通过扩展代理类&#xff0c;进行一些功能的附加与增强。值得注意的是&#xff0c;代理类和被代理类应该共同实现一个接口&#xff0c;或者是共同继承某个类。

静态代理模式缺点&#xff1a;随着被代理对象的增多&#xff0c;我们发现代理对象的压力越来越大&#xff0c;而且里面书写的代码也是比较臃肿的

上面介绍的是静态代理的内容&#xff0c;为什么叫做静态呢&#xff1f;因为它的类型是事先预定好的&#xff0c;比如上面代码中的 Intermediary这个类。下面要介绍的内容就是动态代理。

JDK动态代理

使用步骤

1、 新建一个接口

2、 为接口创建一个实现类

3、 创建代理类实现java.lang.reflect.InvocationHandler接口&#xff0c;重写invoke方法

4、 测试

JDK动态代理实现代码

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//在这个类中书写动态产生代理对象的方法
public class MyInv implements InvocationHandler{private LetRoom lr;public void setLr(LetRoom lr) {this.lr &#61; lr;}//执行该方法就会动态产生代理对象public Object getProxy() {/*** 参数一&#xff1a;保证类型是ClassLoader* 参数二&#xff1a;接口的class数组* 参数三&#xff1a;参数类型是InvocationHandler即可*/Object o &#61; Proxy.newProxyInstance(MyInv.class.getClassLoader(), new Class[]{LetRoom.class}, this);return o;//返回中介}//这个方法就类似与书写中介中的zf()方法&#64;Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/** proxy:代理对象——中介* method:代理对象中的方法* args&#xff1a;参数--null*/System.out.println("--收取推荐费100元--");//调用了指定房东的zf()方法Object invoke &#61; method.invoke(lr, args);System.out.println("--收取管理费200元--");return invoke;}
}

测试类

public class Test {public static void main(String[] args) {MyInv my &#61; new MyInv();//设置具体的房东my.setLr(new Landlord2());//产生中介代理对象LetRoom proxy &#61; (LetRoom) my.getProxy();proxy.zf(); }
}

d927214ebd457152417865314c38efd1.png
测试结果

结构示意图&#xff1a;

2d41d85869c2937cebea3c5328ee601a.png
结果示意图

JDK代理模式缺点&#xff1a;

我们发现JDK代理模式是必须需要有接口的操作&#xff0c;如果没有对应的接口&#xff0c;这个时候JDK代理就没有办法使用

CGLIB动态代理

通过“继承”可以继承父类所有的公开方法&#xff0c;然后可以重写这些方法&#xff0c;在重写时对这些方法增强&#xff0c;这就是CGLIB的思想。

使用步骤

1、 创建一个实现类

2、导入所需的包

a53bb94436906c674ad637c25a437c93.png

3、 创建代理类实现net.sf.cglib.proxy.MethodInterceptor接口&#xff0c;重写intercept方法

4、 测试

CGLIB动态代理代码实现

import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class MethodInv implements MethodInterceptor{//产生代理类对象public Object getProxy() {Enhancer en &#61; new Enhancer();//类似于之前的接口en.setSuperclass(Landlord.class);en.setCallback(this);//是整个设置的内容生效Object o &#61; en.create();return o;}&#64;Overridepublic Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {/*** object:被代理对象* method:被代理对象的方法* objects:参数* methodProxy&#xff1a;代理对象中方法*/System.out.println("--收取推荐费100元--");//调用真正房东的zf()方法Object o1 &#61; methodProxy.invokeSuper(object, objects);System.out.println("--收取管理费200元--");return o1;}}

测试类&#xff1a;

public class Test {public static void main(String[] args) {MethodInv m &#61; new MethodInv();Landlord proxy &#61; (Landlord) m.getProxy();proxy.zf();}
}

1e02a03438dd599641a77b2b492ff9ed.png
测试结果

JDK与Cglib动态代理对比&#xff1f;

1、JDK动态代理只能代理实现了接口的类&#xff0c;没有实现接口的类不能实现JDK的动态代理&#xff1b;

2、Cglib动态代理是针对类实现代理的&#xff0c;运行时动态生成被代理类的子类拦截父类方法调用&#xff0c;因此不能代理声明为final类型的类和方法&#xff1b;

动态代理和静态代理的区别&#xff1f;

1、静态代理在代理前就知道要代理的是哪个对象&#xff0c;而动态代理是运行时才知道&#xff1b;

2、静态代理一般只能代理一个类&#xff0c;而动态代理能代理实现了接口的多个类&#xff1b;

Spring如何选择两种代理模式的&#xff1f;

1、如果目标对象实现了接口&#xff0c;则默认采用JDK动态代理&#xff1b;

2、如果目标对象没有实现接口&#xff0c;则使用Cglib代理&#xff1b;

3、如果目标对象实现了接口&#xff0c;但强制使用了Cglib&#xff0c;则使用Cglib进行代理

原文链接&#xff1a;jdk动态代理和cglib动态代理详解_分享传递价值-CSDN博客_jdk 或 cglib 代理



推荐阅读
author-avatar
谢冬彬_868
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有