静态代理和动态代理案例介绍

  • 1、代理模式概念
  • 2、代理模式分类
  • 3、静态代理(1)
    • 【1】目标
    • 【2】实现
      • 【2.1】创建项目
      • 【2.2】定义HouseAgencyCompany
      • 【2.3】定义HouseOwner、HouseProxy
      • 【2.4】定义Customer
      • 【2.5】运行结果
    • 【3】静态代理小结
  • 4、动态代理
    • 【1】思考
    • 【2】动态代理概述
    • 【3】jdk动态代理(2)
      • 【3.1】目标
      • 【3.2】实现
        • 【3.2.1】创建项目
        • 【3.2.2】修改Customer
        • 【3.2.3】测试结果
      • 【3.3】小结
    • 【4】cglib动态代理(3)
      • 【4.1】思考
      • 【4.2】实现
        • 【4.2.1】创建项目
        • 【4.2.2】修改Customer
        • 【4.2.4】测试结果
      • 【4.3】小结
    • 【5】动态代理小结
  • 5、使用工厂模式+单例模式实现代理模式
    • ProxyFactory 类
    • JdkProxy单元测试
    • CglibProxy单元测试

1、代理模式概念

我很忙,忙的没空理你,那你要找我呢,就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,被代理人虽然不想干活,但是代理的人能干活呀。

生活中的房屋中介

2、代理模式分类

静态代理:

 【定义】在程序运行之前,代理类.class文件就已经被创建【实现】由程序员创建或特定工具自动生成源代码,在对其编译

动态代理:

 【定义】程序运行时通过反射机制动态创建的,对方法的【增强】,不需要修改源码【实现】基于接口:JDK动态代理基于子类:CGLib动态代理

3、静态代理(1)

【1】目标

使用静态代理的方式,完成通过房产中介租房的操作;

【2】实现

生活中的房屋中介抽象:

步骤:
1、创建项目;
2、定义接口:HouseAgencyCompany及接口中租房的方法:rentingHouse;
3、定义房主类:HouseOwner ,中介类 HouseProxy,均实现接口HouseAgencyCompany;
4、定义租客类:Customer调用HouseProxy完成租房

【2.1】创建项目

新建项目

【2.2】定义HouseAgencyCompany

/*** @Description:中介公司*/
public interface HouseAgencyCompany {/*** @Description 租房子*/void rentingHouse();
}

【2.3】定义HouseOwner、HouseProxy

    /*** @Description:被代理人(房东)*/
public class HouseOwner implements HouseAgencyCompany {@Overridepublic void rentingHouse() {System.out.println("房东签合同");}}
/*** @Description:中介(代理人)*/
public class HouseProxy implements HouseAgencyCompany {/*** 被代理人*/private HouseOwner houseOwner;public HouseProxy() {this.houseOwner = new HouseOwner();}@Overridepublic void rentingHouse() {System.out.println("中介带看房子");System.out.println("中介约房东");houseOwner.rentingHouse();System.out.println("中介完成租房");}
}

【2.4】定义Customer

import org.junit.jupiter.api.Test;/*** @Description:租客*/
public class Customer {@Testpublic void needHouse(){HouseOwner houseOwner  = new HouseOwner();houseOwner.rentingHouse();System.out.println("==================================");HouseAgencyCompany houseAgencyCompany = new HouseProxy();houseAgencyCompany.rentingHouse();}
}

【2.5】运行结果

【3】静态代理小结

1、静态代理:在程序运行前手动创建代理类,代理类和目标类需要实现相同接口;

4、动态代理

【1】思考

静态代理有什么问题?如果目标类中有多个方法都需要增强,我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改

【2】动态代理概述

代理类在程序运行时创建的方式被成为动态代理。
也就是说,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的动态生成的。
相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

【3】jdk动态代理(2)

jdk动态代理:

必须基于接口java.lang.reflect.Proxy:Java动态代理机制的主类,提供了一组静态方法来为一组接口动态地生成代理类及其实例。
//方法1: 该方法用于获取指定动态代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)//方法2:该方法用于获取关联于指定类装载器和一组接口的动态代理对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)//方法3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)//方法4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理对象:
//1、类加载器 2、接口数组、调用处理器(增强部分的业务代码)
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

java.lang.reflect.InvocationHandler:

调用处理器接口,它自定义了一个invoke方法,用于集中处理在动态代理对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理对象时都需要指定一个实现了该接口的调用处理器对象。

InvocationHandler的核心方法:

//该方法负责集中处理动态代理类上的所有方法调用。
//第一个参数是代理对象,第二个参数是被调用的方法对象,第三个方法是调用参数。
//调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行。
Object invoke(Object proxy, Method method, Object[] args)

【3.1】目标

 使用jdk动态代理的方式,增强租房方法,使得租房方法前后打印输入日志信息;

【3.2】实现

【3.2.1】创建项目

【3.2.2】修改Customer

    import org.junit.Test;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/*** @Description:租客*/public class Customer {HouseOwner houseOwner = new HouseOwner();@Testpublic void needHouse(){//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理对象://1、目标类的加载器 2、目标类接口 3、调用处理器(增强部分的业务代码)HouseAgencyCompany houseProxy = (HouseAgencyCompany) Proxy.newProxyInstance(houseOwner.getClass().getClassLoader(),houseOwner.getClass().getInterfaces(), new InvocationHandler() {//第一个参数是代理对象,第二个参数是被调用的方法对象(rentingHoues),第三个方法是调用参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//前置增强System.out.println("中介公司让中介带客户看房");Object object = method.invoke(houseOwner, args);//后置增强System.out.println("中介公司让中介完成租房业务");return object;}});houseProxy.rentingHoues();}}

【3.2.3】测试结果

【3.3】小结

1、JDK动态代理:基于接口的;
2、JDK动态代理实现要点:Proxy类newProxyInstance静态方法InvocationHandler增强方法

【4】cglib动态代理(3)

【4.1】思考

如果目标类没有实现接口呢?那么就无法使用JDK的动态代理,因此这种方式有其局限性,必须实现一个接口。
可以使用的方案:使用CGLIB动态代理:基于子类(包含本类)

net.sf.cglib.proxy.Enhancer

Enhancer类是CGLib中的一个字节码增强器,作用用于生成代理对象,跟上一章所学的Proxy类相似,常用方式为:

 //方法1:该方法用于为指定目标类、回调对象 1、类的类型,2、调用处理器public static Object create(Class type, Callback callback)

net.sf.cglib.proxy.MethodInterceptor

//方法1:
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;

【4.2】实现

【4.2.1】创建项目

【4.2.2】修改Customer

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;import java.lang.reflect.Method;/*** @Description:*/
public class Customer {@Testpublic void needHouse(){System.out.println("=====================");//create():该方法用于为指定目标类、回调对象 1、被代理的类型,2、拦截方法//代理模式下的租房HouseOwner houseOwnerProxy = (HouseOwner) Enhancer.create(HouseOwner.class,new MethodInterceptor() {//1、代理类 2、执行的目标方法 3、方法参数 4、方法的代理@Overridepublic Object intercept(Object o, Method method,Object[] objects, MethodProxy methodProxy) throws Throwable {//增强System.out.println("中介公司让中介带客户看房");//返回结果methodProxy.invokeSuper(o, objects);System.out.println("中介公司让中介完成租房业务");return null;}});houseOwnerProxy.renttingHouse();}
}

【4.2.4】测试结果

【4.3】小结

1、Cglib动态代理:基于类,无需实现接口;
2、被代理的目标类不能被final修饰

【5】动态代理小结

通过动态代理可以完成对已有方法的功能的增强:
1、JDK动态代理要求:被代理对象至少实现一个接口应用场景:被代理对象有接口2、CGLIB动态代理要求:被代理类上不能用static、final修饰应用场景:被代理对象没有实现接口

5、使用工厂模式+单例模式实现代理模式

案例代码

ProxyFactory 类

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @ClassName: ProxyFactory * @Description: 使用工厂模式 + 单例模式实现 JdkProxy* @Author: wang xiao le* @Date: 2023/03/18 21:50**/
public class ProxyFactory {private ProxyFactory() {}private static class JdkProxyFactoryInstance {public static final ProxyFactory INSTANCE = new ProxyFactory();}public static ProxyFactory getInstance() {return JdkProxyFactoryInstance.INSTANCE;}/*** Jdk动态代理** @param obj 委托对象* @return 代理对象*/public Object getJdkProxy(Object obj) {//第一个参数:目标类的加载器,第二个参数:目标类的接口,第三个参数:调用处理器return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),new InvocationHandler() {//第一个参数:代理类,//第二个参数:执行的目标方法,这里指的是:rentingHouse//第三参数:方法参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//前置增强System.out.println("中介公司:我安排中介带你去看房子");Object invoke = method.invoke(obj, args);//后置增强System.out.println("中介公司:欢迎下次光临");return invoke;}});}/*** 使用cglib动态代理生成代理对象* @param obj 委托对象* @return*/public Object getCglibProxy(Object obj) {//第一个参数:被代理类的类型 第二个参数:拦截方法return Enhancer.create(obj.getClass(),new MethodInterceptor() {@Override//第一个:代理类,第二个是:执行的目标方法,第三个:方法参数,第四个:方法的代理public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("房东儿子:我爸身体不好,让我来带i看房子");methodProxy.invokeSuper(o, objects);System.out.println("房东儿子:我爸身体不好,后面有什么事情你可以找我");return null;}});}
}

JdkProxy单元测试


@SpringBootTest
class JdkProxyTests {@Testpublic void  needHouse(){HouseOwner houseOwner = new HouseOwner();System.out.println("=============================");//第一个参数:目标类的加载器,第二个参数:目标类的接口,第三个参数:调用处理器HouseAgencyCompany houseAgencyCompany = (HouseAgencyCompany) Proxy.newProxyInstance(HouseAgencyCompany.class.getClassLoader(),houseOwner.getClass().getInterfaces(),new InvocationHandler() {//第一个参数:代理类,//第二个参数:执行的目标方法,这里指的是:rentingHouse//第三参数:方法参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//前置增强System.out.println("中介公司:我安排中介带你去看房子");Object invoke = method.invoke(houseOwner, args);//后置增强System.out.println("中介公司:欢迎下次光临");return invoke;}});houseAgencyCompany.rentingHouse();//=============================//中介公司:我安排中介带你去看房子//房东:签合同//中介公司:欢迎下次光临}@Testvoid factoryTest() {ProxyFactory jdkProxyFactory = ProxyFactory.getInstance();HouseOwner houseOwner = new HouseOwner();HouseAgencyCompany houseAgencyCompany = (HouseAgencyCompany) jdkProxyFactory.getJdkProxy(houseOwner);houseAgencyCompany.rentingHouse();//中介公司:我安排中介带你去看房子//房东:签合同//中介公司:欢迎下次光临}
}

CglibProxy单元测试


@SpringBootTest
class CglibProxyTests {@Testvoid factoryTest() {HouseOwner houseOwner = new HouseOwner();//创建代理对象,通过Jdk动态代理对原有对象中的方法进行增强ProxyFactory jdkProxyFactory = ProxyFactory.getInstance();HouseAgencyCompany houseAgencyCompany = (HouseAgencyCompany) jdkProxyFactory.getCglibProxy(houseOwner);//使用增强后的类houseAgencyCompany.rentingHouse();//房东儿子:我爸身体不好,让我来带i看房子//房东:签合同//房东儿子:我爸身体不好,后面有什么事情你可以找我}@Testpublic void  needHouse(){//第一个参数:被代理类的类型 第二个参数:拦截方法HouseOwner houseOwner = (HouseOwner) Enhancer.create(HouseOwner.class,new MethodInterceptor() {@Override//第一个:代理类,第二个是:执行的目标方法,第三个:方法参数,第四个:方法的代理public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("房东儿子:我爸身体不好,让我来带i看房子");methodProxy.invokeSuper(o, objects);System.out.println("房东儿子:我爸身体不好,后面有什么事情你可以找我");return null;}});houseOwner.rentingHouse();//房东儿子:我爸身体不好,让我来带i看房子//房东:签合同//房东儿子:我爸身体不好,后面有什么事情你可以找我}}

静态代理和动态代理案例介绍相关推荐

  1. Spring AOP中的静态代理和动态代理的原理和实践

    对于最近博主最近写博客的兴致大发,我也在思考:为什么而写博客?在互联网时代,无论你是牛人大咖,还是小白菜鸟,都有发表自己看法的权利.无论你是对的还是错的,都会在这个平台上找到答案.所以,我会尽可能去写 ...

  2. Spring中的静态代理和动态代理

    一.什么是代理? 代理是一种设计模式,提供了对目标对象另外的访问方式,即通过代理对象访问目标对象.可以不修改目标对象,对目标对象功能进行拓展.在我们学习Spring的时候就会发现,AOP(面向切面编程 ...

  3. 静态代理、动态代理概念及使用

    文章目录 1. 为什么要用静态代理 2. 静态代理的实现 3. 静态代理的缺点 4. 动态代理 4.1 JDK动态代理 4.1.1 InvocationHandler 4.1.2 Class 4.1. ...

  4. Java、Android静态代理与动态代理

    代理 (1) 什么是代理? 大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用.具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法.这个就好比 商户----&g ...

  5. 架构设计之设计模式 (二) 静态代理和动态代理--间接“美”

    生活中有很多例子是间接来控制和访问的,比如你找一个人不自己亲自去,而是让别人代替去做这就是最简单的代理模式,是一种间接通信的例子,对象间的间接通信也同样是面向对象设计中的一条重要的"审美观& ...

  6. 代理模式——静态代理,动态代理(JDK代理和CGLib代理)

    概述 由于某些原因需要给某对象提供一个代理以控制对该对象的访问. 这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介. Java中的代理按照代理类生成时机不同又分为 ...

  7. Java静态代理、动态代理与CGLib代理

    java的动态代理举足轻重,它同反射原理一直是许多框架的底层实现.今天唠一下. 一.代理模式 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标 ...

  8. 浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试

    文章目录 Java的静态代理 静态代理的优缺点 ABAP的静态代理 Spring AOP的动态代理 JDK动态代理的优缺点 CGLIB动态代理的优缺点 ABAP CGLIB的模拟实现 ABAP Pre ...

  9. 代理模式详解(静态代理和动态代理的区别以及联系)

    原文链接:https://www.cnblogs.com/takumicx/p/9285230.html 1. 前言 代理模式可以说是生活中处处可见.比如说在携程上定火车票,携程在这里就起到了一个代理 ...

最新文章

  1. 机器学习知识点(五)梯度下降法Java实现
  2. win10系统安装Redis3.2.100
  3. java final 意思_在java中一个类被声明为final类型,表示的意思是()。
  4. php 单一职责原则,Laravel深入学习8 - 单一责任原则
  5. linux下vi常用命令——读《鸟哥的linux私房菜》整理
  6. sql 标量子查询_SQL Server 2017:标量子查询简化
  7. 洛谷 P1426 小鱼会有危险吗(C语言)
  8. 以太坊 交易 data字段 内容是什么
  9. 服务器内存是用接近完毕
  10. 微信公众号迁移公证书需要哪些材料?账号迁移流程来了
  11. python 判断数字是奇数还是偶数
  12. 影响我一生的两本书(02)_huadingjin_新浪博客
  13. i5 10400f和i7 8700k哪个好
  14. Nginx之13运筹帷幄 - (VeryNginx)
  15. c++编程规范和范例
  16. 赛诺菲巴斯德宣布建立专属mRNA疫苗卓越中心;​葛兰素史克单片双药艾滋病治疗药物多伟托在中国上市 | 医药健闻...
  17. 十大经典管理哲学故事
  18. 微信跳一跳python自动代码解读1.0
  19. offsetParent解释
  20. mac系统免费软件 GoodNotes 5.8.6 中文版 (最好的手写笔记应用)

热门文章

  1. 一个大胆的猜想:如果GitHub的数据库用的是OceanBase
  2. 真实3D纹理绘制工具:Mari for mac(支持big sur) v4.7v1
  3. 蓝桥杯 Java 饮料换购
  4. 2013年最精致的企业网站设计欣赏【系列四】
  5. java的jlabel_java – JLabel在另一个JLabel之上
  6. (韩顺平)08 面向对象编程(中级部分)(自用)
  7. java group by_Java实现GroupBy/分组TopN功能
  8. dnf安徒恩服务器不稳定,DNF安徒恩开团后掉线那些事 网友:这时才体会到混子的重要性...
  9. 【华为OD机试真题2023 JAVAJS】上班之路
  10. Auto.js实现自动授权截屏权限