首页 > 其他分享 >代理模式(静态代理和动态代理)

代理模式(静态代理和动态代理)

时间:2024-03-26 16:33:40浏览次数:20  
标签:name 静态 void 代理 eat println 动态 public

1.静态代理

        静态代理中代理类与被代理类都需要实现同一个接口,这就说明我们的一个静态代理类只能代理一个类,并且还要事先知道我们要代理哪个类才能写代理类,如果我们有其他类还想使用代理那就必须再写一个代理类。

【1】测试案例:法外狂徒张三叫律师打官司

package com.jlx.test;

public class Test1 {
    public static void main(String[] args) {
        Person person =new Person("法外狂徒张三");
        Court court=new Lawyer(person);
        court.doCourt();
    }
}
//接口
interface Court{
    void doCourt();
}

//代理类
class Lawyer implements Court{
    private Person person;

    public Lawyer(Person person) {
        this.person = person;
    }

    @Override
    public void doCourt() {
        System.out.println("律师取证:视频证明张三当时正在旅游,不在案发现场");
        System.out.println("律师总结:张三不可能去杀人");
        person.doCourt();
    }
}

//被代理类
class Person implements Court{
    private String name;
    public Person(String name) {
        this.name = name;
    }

    @Override
    public void doCourt() {
        System.out.println(name+"说:我没有杀人");
    }
}

【2】测试结果

注:在实际开发中我们是可能是有非常多的类是需要被代理的,并且事先我们可能并不知道我们要代理哪个类。所以如果继续使用静态代理反而会增加许多的工作量,并且效率低下,代码复用率也不好。


2.动态代理

动态代理可以针对于一些不特定的类或者一些不特定的方法进行代理,我们可以在程序运行时动态的变化代理的规则,代理类在程序运行时才创建的代理模式成为动态代理。这种情况下,代理类并不是在Java代码中定义好的,而是在程序运行时根据我们的在Java代码中的“指示”动态生成的
      Proxy  动态代理 JDK动态代理         面向接口
      cglib    动态代理 第三方动态代理     面向父类

2.1Proxy动态代理

【1】案例测试,法外狂徒张三吃饭

package com.jlx.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestProxy {
    public static void main(String[] args) {
        Dinner dinner=new Person1("法外狂徒张三");
        //    通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
//        ClassLoader loader,被代理的对象的类加载器
        ClassLoader classLoader = dinner.getClass().getClassLoader();
//        Class<?>[] interfaces,被代理对象所实现的所有接口
        Class[] interaces= dinner.getClass().getInterfaces();
//        InvocationHandler h,执行处理器对象,专门用于定义增强的规则
        InvocationHandler handler = new InvocationHandler(){
            // invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                Object proxy, 代理对象
//                Method method,被代理的方法
//                Object[] args,被代理方法运行时的实参
                Object res=null;
                if(method.getName().equals("eat")){
                    System.out.println("饭前洗手");
                    // 让原有的eat的方法去运行
                    res =method.invoke(dinner, args);
                    System.out.println("饭后刷碗");
                }else{
                    // 如果是其他方法,那么正常执行就可以了
                    res =method.invoke(dinner, args);
                }
                return res;
            }
        };
        Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler);
        dinnerProxy.eat("包子");
        dinnerProxy.drink();
    }
}
interface Dinner{
    void eat(String foodName);
    void drink();
}
class Person1 implements Dinner{
    private String name;
    public Person1(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝茶");
    }
}
class Student implements Dinner{
    private String name;
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在食堂吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝可乐");
    }
}

【2】测试结果 

2.2cglib动态代理

package com.jlx.test;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class TestCglib {
    @Test
    public void testCglib(){
        Person2 person =new Person2();
        // 获取一个Person的代理对象
        // 1 获得一个Enhancer对象
        Enhancer enhancer=new Enhancer();
        // 2 设置父类字节码
        enhancer.setSuperclass(person.getClass());
        // 3 获取MethodIntercepter对象 用于定义增强规则
        MethodInterceptor methodInterceptor=new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                /*Object o,  生成之后的代理对象 personProxy
                Method method,  父类中原本要执行的方法  Person>>> eat()
                Object[] objects, 方法在调用时传入的实参数组
                MethodProxy methodProxy  子类中重写父类的方法 personProxy >>> eat()
                */
                Object res =null;
                if(method.getName().equals("eat")){
                    // 如果是eat方法 则增强并运行
                    System.out.println("饭前洗手");
                    res=methodProxy.invokeSuper(o,objects);
                    System.out.println("饭后刷碗");
                }else{
                    // 如果是其他方法 不增强运行
                    res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
                }
                return res;
            }
        };
        // 4 设置methodInterceptor
        enhancer.setCallback(methodInterceptor);
        // 5 获得代理对象
        Person2 personProxy = (Person2) enhancer.create();
        // 6 使用代理对象完成功能
        personProxy.eat("包子");
    }
}
class Person2  {
    public Person2( ) {
    }
    public void eat(String foodName) {
        System.out.println("张三正在吃"+foodName);
    }
}

【2】测试结果

标签:name,静态,void,代理,eat,println,动态,public
From: https://blog.csdn.net/weixin_53869844/article/details/137046093

相关文章

  • jinja2 通过Template. make_module 进行动态macro 创建以及macro 方法调用
    实际属于一个小技巧,可以实现比较灵活的jinja2扩展,是从dbt对于macro的处理部分学习到的参考代码app.pyfromjinja2importEnvironment env=Environment() #定义macro的内容macro_template="""{%macromydemo(name,age)-%}{{name......
  • .NET Emit 入门教程:第五部分:动态生成方法(MethodBuilder 与 DynamicMethod)
    前言:当我们涉及到在运行时生成和定义方法时,便需要使用到C#中的两个关键类之一:MethodBuilder 或 DynamicMethod。这两者都属于反射(Reflection.Emit)的一部分,允许我们以动态的方式创建方法。两者各有侧重,使用方式大体相同,本篇文章我们先介绍MethodBuilder,再介绍DynamicMethod,......
  • nexus 代理 go
    创建 BlobStores创建Repositoriesnginx配置server{listen19000;server_namelocalhost;#设置代理访问日志access_loglogs/yum.access.log;error_loglogs/yum.error.log;location/goproxy/{ proxy_passhtt......
  • Dubbo23_解决Dubbo无法发布被事务代理的Service问题7
    一、问题展示前面我们已经完成了Dubbo的入门案例,通过入门案例我们可以看到通过Dubbo提供的标签配置就可以进行包扫描,扫描到@Service注解的类就可以被发布为服务。但是我们如果在服务提供者类上加入@Transactional事务控制注解后,服务就发布不成功了。原因是事务控制的底层原......
  • blog-engine-06-pelican 静态网站生成 支持 markdown 和 reST 语法
    拓展阅读blog-engine-01-常见博客引擎jekyll/hugo/Hexo/Pelican/Gatsby/VuePress/Nuxt.js/Middleman对比blog-engine-02-通过博客引擎jekyll构建githubpages博客实战笔记blog-engine-02-博客引擎jekyll-jekyll博客引擎介绍blog-engine-02-博客引擎jekyll-jekyll如何......
  • 静态数据成员的应用
    classStudent{//1.数据成员privateStringname;privateStringsex;publicstaticStringschool="岳麓书院";//公布静态数据成员//2.省略构造方法;//3.省略setter和getter方法;//4.功能方法publicvoiddisplay(){......
  • C++动态内存管理
    目录C/C++内存分配C++内存管理C++内存管理介绍C++内存管理使用C++内存管理基本语法operatornew和operatordelete函数定位new表达式(placement-new)基本语法使用场景malloc/free和new/delete相同点不同点C/C++内存分配在C语言动态内存管理章节已经了解到内......
  • 动态规划——线性dp
    数字三角形//从上到下#include<iostream>#include<algorithm>usingnamespacestd;constintN=510,INF=1e9;intn;inta[N][N];intf[N][N];intmain(){scanf("%d",&n);for(inti=1;i<=n;i++)for(int......
  • Django框架静态文件
    【一】静态文件配置说明【1】模板文件通常html文件都会放在templates文件夹下【2】资源文件资源文件也就是jQuery,bootstrap这些前端框架这些都统称为静态文件,通常默认是放在static文件夹里面的static内部又通常分为以下三部分cssjssimgplugins【二】静态文件配......
  • 动态尺寸加载libpag文件白边问题解决方案
    加载pag文件时,最理想的情况是canvas的宽高和pag资源文件的宽高一致,或比例一致。否则就会出现四周白边(页面底色),除非是按平铺的样式进行设置(源码暂未找到对应方法)。而对于页面宽高不定的情况下,就无法保证pag文件能适配页面,如果pag文件底色和父级页面底色不一致,就会表现出来......