首页 > 编程语言 >java基础——静态代理和动态代理

java基础——静态代理和动态代理

时间:2023-04-07 15:48:23浏览次数:56  
标签:java 静态 System 接口 代理 println public out

java代理模式有静态代理和动态代理两种实现方式

一、静态代理

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

  优点:

    可以在不修改目标对象的前提下扩展目标对象的功能。
  缺点:
    冗余:由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
    不易维护:一旦接口增加方法,目标对象与代理对象都要进行修改。

 

  **静态代理的特点**

    1、目标角色固定

    2、在应用程序执行前就得到目标角色

    3、代理对象会增强目标对象的行为

    4、有可能存在多个代理 引起"类爆炸"(缺点)

 

二、动态代理

  动态代理利用了 JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。

  动态代理又被称为 JDK 代理或接口代理。静态代理与动态代理的区别主要在:

    1、静态代理在编译时就已经实现,编译完成后代理类是一个实际的 class 文件
    2、动态代理是在运行时动态生成的,即编译完成后没有实际的 class 文件,而是在运行时动态生成类字节码,并加载到 JVM 中
  注意:动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

  JDK 中生成代理对象主要涉及两个类,第一个类为 java.lang.reflect.Proxy,通过静态方法 newProxyInstance 生成代理对象,第二个为 java.lang.reflect.InvocationHandler 接口,通过 invoke 方法对业务进行增强

  **动态代理的特点**

    1、目标对象不固定

    2、在应用程序执行时动态创建目标对象

    3、代理对象会增强目标对象的行为

三、代码实例

  用代码模拟一下结婚和婚庆公司演示静态代理

// 定义一个接口结婚的接口
interface  Mary{
    void mary() ;
}

//每个人都要结婚
class You implements Mary{//真实角色

    @Override
    public void mary() {
        System.out.println("要结婚了,很开心...");
    }
}


//婚庆公司---代理角色
class WeddingCompany implements Mary{
    //声明一个接口Mary类型变量
    private Mary mary ;
    public WeddingCompany(Mary mary){ //形式参数是一个接口,需要接口实现类对象
        this.mary = mary ;
    }

    @Override
    public void mary() {
        //代理角色需要帮助真实角色完成一件 "结婚这件事情"
        System.out.println("结婚之前,需要布置婚礼现场....");
        mary.mary() ;
        System.out.println("结婚之后,给婚庆公司付尾款....");
    }
}

public class StaticProxyDemo {
    public static void main(String[] args) {

        //没有使用静态代理之前
        //接口多态或者是具体类new 具体类
        Mary mary = new You() ;
        mary.mary() ;
        System.out.println("-----------------------------------------");
        //使用静态代理
        You you = new You() ;
        //创建代理角色
        WeddingCompany weddingCompany = new WeddingCompany(you) ;
        weddingCompany.mary();
    }
}
输出结果:

要结婚了,很开心… ----------------------------------------- 结婚之前,需要布置婚礼现场… 要结婚了,很开心… 结婚之后,给婚庆公司付尾款…

  用代码模拟一下结婚和婚庆公司演示动态代理

  1、针对用户访问的数据接口

public interface UserDao {
    /**
     * 添加功能
     */
    void add() ;

    /**
     * 修改功能
     */
    void update() ;

    /**
     * 查询功能
     */
    void select() ;

    /**
     * 删除功能
     */
    void delete() ;
}

  2、针对用户数据访问接口的实现

public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("添加功能");
    }

    @Override
    public void update() {
        System.out.println("修改功能") ;
    }

    @Override
    public void select() {
        System.out.println("查询功能");
    }

    @Override
    public void delete() {
        System.out.println("删除功能");
    }
}

  3、版本2:对业务方法 add,update,select.delete进行增强

public class UserDaoImpl2 implements UserDao {
    @Override
    public void add() {
        System.out.println("权限校验") ;

        System.out.println("执行添加功能");

        System.out.println("产生日志文件");
    }

    @Override
    public void update() {
        System.out.println("权限校验") ;

        System.out.println("执行修改功能");

        System.out.println("产生日志文件");
    }

    @Override
    public void select() {

        System.out.println("权限校验") ;

        System.out.println("执行查询功能");

        System.out.println("产生日志文件");
    }

    @Override
    public void delete() {

        System.out.println("权限校验") ;

        System.out.println("执行删除功能");

        System.out.println("产生日志文件") ;
    }
}
/*Proxy类下边的方法newProxyInstance
*   public static Object newProxyInstance(ClassLoader loader,   参数1:实现的接口的类加载器
*                                       Class<?>[] interfaces,  参数2:基于接口的字节码文件对象数组
*                                       InvocationHandler h)    参数3:是接口InvocationHandler :代理的处理程序
*                                throws IllegalArgumentException

*                                                    参数3是一个接口:自定一个类实现这个接口
*                                                       重写这个接口中的invoke方法
*                                                Object invoke(Object proxy,Method method,Object[] args)throws Throwable
*/

 

  4、基于代理的处理程序

public class MyInvocation  implements InvocationHandler {

    //要针对谁产生代理: ud                 UserDao ud = new UserDaoImpl() ;
    private Object target ;  //因为代理角色可以是任意Java类型,所以用Object
    public MyInvocation(Object target){
        this.target = target ;
    }


    //方法的返回值就是代理对象
    @Override                           //就是我们的接口的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("权限校验") ;

        //调用接口的列表自己的方法:update(),delete(),add(),select()
        //当前实例--->真实角色
        Object obj = method.invoke(target, args); //代理角色产生

        System.out.println("产生日志文件");
        return obj;
    }
}

 

  5、测试类

public class JdkProxyDemo {
    public static void main(String[] args) {

        //接口多态:测试UserDao
        UserDao ud = new UserDaoImpl() ; //真实角色
        //版本1:现在需要对功能增强,这个代码不合适!
        ud.add();
        ud.update();
        ud.select();
        ud.delete();
        System.out.println("----------------------------------");

        UserDao ud2 = new UserDaoImpl2() ;
        ud2.add();
        ud2.update();
        ud2.select();
        ud2.delete();

        System.out.println("----------------Jdk动态代理------------------");

        //前提示需要一个接口:UserDao

        MyInvocation handler = new MyInvocation(ud) ;
        // public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
        UserDao proxyInstance = (UserDao) Proxy.newProxyInstance(
                ud.getClass().getClassLoader(),
                ud.getClass().getInterfaces(),
                handler);
        proxyInstance.add();
        proxyInstance.update();
        proxyInstance.select();
        proxyInstance.delete();
    }
}

结果:

添加功能
​ 修改功能
​ 查询功能
​ 删除功能
​ ----------------------------------

​ 权限校验
​ 执行添加功能
​ 产生日志文件
​ 权限校验
​ 执行修改功能
​ 产生日志文件
​ 权限校验
​ 执行查询功能
​ 产生日志文件
​ 权限校验
​ 执行删除功能
​ 产生日志文件
​ ----------------Jdk动态代理------------------
​ 权限校验
​ 添加功能
​ 产生日志文件
​ 权限校验
​ 修改功能
​ 产生日志文件
​ 权限校验
​ 查询功能
​ 产生日志文件
​ 权限校验
​ 删除功能
​ 产生日志文件

 

 

参考:

https://blog.csdn.net/zjshuster/article/details/126439883

https://blog.csdn.net/longzorg_cn/article/details/129115728 

https://blog.csdn.net/m0_67499084/article/details/124810718 

标签:java,静态,System,接口,代理,println,public,out
From: https://www.cnblogs.com/51python/p/17296362.html

相关文章

  • 如何在Java中做基准测试?JMH使用初体验
    大家好,我是王有志,欢迎和我聊技术,聊漂泊在外的生活。快来加入我们的Java提桶跑路群:共同富裕的Java人。最近公司在搞新项目,由于是实验性质,且不会直接面对客户的项目,这次的技术选型非常激进,如,直接使用了Java17。作为公司里练习两年半的个人练习生,我自然也是深度的参与到了技术选......
  • ASEMI代理AD8130ARZ-REEL7原装ADI车规级AD8130ARZ-REEL7
    编辑:llASEMI代理AD8130ARZ-REEL7原装ADI车规级AD8130ARZ-REEL7型号:AD8130ARZ-REEL7品牌:ADI/亚德诺封装:SOIC-8批号:2023+安装类型:表面贴装型AD8130ARZ-REEL7汽车芯片AD8130ARZ-REEL7特征高速AD8130:270兆赫,1090伏/μs@G=+1AD8129:200兆赫,1060伏/μs@G=+10高CMRR最小94dB,直流至100kH......
  • PHPCMS粘贴图片自动上传到服务器(Java版)
    ​ 这种方法是servlet,编写好在web.xml里配置servlet-class和servlet-mapping即可使用后台(服务端)java服务代码:(上传至ROOT/lqxcPics文件夹下)<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%@     page contentType="text/html;cha......
  • Java 自增自减运算符和移位运算符介绍
    摘自JavaGuide(「Java学习+面试指南」一份涵盖大部分Java程序员所需要掌握的核心知识。准备Java面试,首选JavaGuide!)自增自减运算符在写代码的过程中,常见的一种情况是需要某个整数类型变量增加1或减少1,Java提供了一种特殊的运算符,用于这种表达式,叫做自增运算符(++)和自......
  • Java数组
    数组数组的定义数组是相同类型数据的有序集合.数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们.数组声明创建首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的......
  • ASEMI代理AD8065ARTZ-REEL7原装ADI车规级AD8065ARTZ-REEL7
    编辑:llASEMI代理AD8065ARTZ-REEL7原装ADI车规级AD8065ARTZ-REEL7型号:AD8065ARTZ-REEL7品牌:ADI/亚德诺封装:SOT-23-5批号:2023+安装类型:表面贴装型引脚数量:23类型:车规级芯片AD8065ARTZ-REEL7特性特征具备汽车应用资格场效应管输入放大器1pA输入偏置电流低成本高速:14......
  • java 进程假死原因排查
    1.假死现象服务程序假死具有以下特征:1.程序对请求没有任何响应;2.程序请求时没有任何日志输出;3.程序进程存在,通过jps或者ps查看进程,可以看到服务进程存在;2.造成假死的可能原因1.java线程出现死锁,或所有线程被阻塞;2.数据库连接池中的连接耗尽,导致获取数据库连接时永久等......
  • c++之静态库与动态库
    一.代码分发方式代码分发方式有三种: 二.动态库与静态库区别三.C/C++到可执行程序的过程:四总结首先清楚,一般来说源码包含.h+.cpp两个文件,而静态库包含.h+.lib文件,动态库包含.h+.lib+.dll,明显动态库要比静态库的文件要更零散一点;其次,要知道.h/.lib/.dll分别起到什么作用,......
  • Linux 系统配置Java Idea Tomcat 全过程
    环境搭建记录-开发环境搭建:1.IDEA安装https://www.jetbrains.com/idea/download/#section=linux解压后执行bin目录idea.sh运行2.JDK安装下载jdk15官方网站:https://www.oracle.com/java/下载页面:https://www.oracle.com/cn/java/technologies/javase-downloads.html2)安装j......
  • Java中子类重写父类方法的思想本质!
    Java语言中,在子类中定义与父类同返同名同参的方法将会出现“重写(覆写)”,子类将屏蔽父类的相同方法,调用子类的方法将不会调用到父类的该方法。许多初学者也许会被“覆写”一词迷惑,以为覆盖掉了父类的方法,其实这两种方法是同时独立存在的,只是子父类调用该方法的入口不一样,彼......