• java的动态代理


    1. 什么是动态代理

    代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色。Java的动态代理比代理的思想更前进了一步,它可以动态地创建并代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的策略。

    大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。


    2. 代理的使用场景

    (1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。

    (2)我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。

    (3)Spring的AOP机制就是采用动态代理的机制来实现切面编程。Spring Aop学习总结 

    3. 代理分类

    • 静态代理:静态代理是在编译时就将接口、实现类、代理类一股脑儿全部手动完成
    • 动态代理:在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能

    4. 静态代理使用举例

    我们先创建一个接口,java api代理机制求被代理类必须要实现某个接口,对于静态代理方式代理类也要实现和被代理类相同的接口。

    public interface Person {
        public void sayHello(String name);
        public void interduce(String name, int age);
    }
    public class Student implements Person{
        @Override
        public void sayHello(String name) {
            System.out.println("Student sayHello start");
            System.out.println("Hello " + name);
            System.out.println("Student sayHello end");
        }
    
        @Override
        public void interduce(String name, int age){
            System.out.println("Student interduce start");
            System.out.println("My name is " + name + ". I'm " + age + " years old");
            System.out.println("Student interduce end");
        }
    }
    import java.lang.reflect.Proxy;
    
    public class StaticProxyTest implements Person{
        private Person person;
    
        public StaticProxyTest(Person person){
            this.person = person;
        }
    
        @Override
        public void sayHello(String name){
            System.out.println("Static Proxy Test sayHello begin");
            person.sayHello(name);
            System.out.println("Static Proxy Test sayHello end");
        }
    
        @Override
        public void interduce(String name, int age){
            System.out.println("Static Proxy Test interduce start");
            person.interduce(name, age);
            System.out.println("Static Proxy Test interduce end");
        }
    
        public static void main(String[] args){
            Student student = new Student();
            StaticProxyTest staticProxyTest = new StaticProxyTest(student);
            staticProxyTest.sayHello("static proxy test");
            staticProxyTest.interduce("static proxy test", 1);
        }
    }

    5. 动态代理

    在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface),另一个则是 Proxy(Class)。这一个类和接口是实现我们动态代理所必须用到的。

    每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法: 

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    proxy:  指代我们所代理的那个真实对象
    method:  指代的是我们所要调用真实对象的某个方法的Method对象
    args:  指代的是调用真实对象某个方法时接受的参数

    接下来我们来看看Proxy这个类,Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

    loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
    这样我就能调用这组接口中的方法了
    h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

    动态代理举例:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MyInvocationHandler implements InvocationHandler {
        public Object object;
    
        public MyInvocationHandler(Object object){
            this.object = object;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable{
            System.out.println("MyInvocationHandle proxy begins");
            System.out.println("proxy: " + proxy.getClass().getName());
            System.out.println("method: " + method.getName());
    
            for(Object o : args) System.out.println("arg: " + o);
    
            method.invoke(object, args);
            System.out.println("MyInvocationHandle proxy ends");
            return null;
        }
    
        public static void main(String[] args){
            Student student = new Student();
            MyInvocationHandler myInvocationHandler = new MyInvocationHandler(student);
            Person proxyPerson = (Person) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(),
                    myInvocationHandler);
    
            proxyPerson.sayHello("proxyPersonSayHello");
            proxyPerson.interduce("proxyPersonInterduce", 1);
        }
    }

    参考文档:

    详解java动态代理机制以及使用场景:https://blog.csdn.net/u011784767/article/details/78281384 

    java动态代理作用及源码分析:https://www.jianshu.com/p/9d5ef621f2d1

    java动态代理机制详解:https://www.cnblogs.com/xiaoluo501395377/p/3383130.html

  • 相关阅读:
    javascript里面this机制的几个例子
    把List<string>集合,编程string,并以“,”号分割
    比较集合List<T>集合,前后多了哪些数据,少了哪些数据Except
    c# Web.config中 windows连接数据库
    MVC之图片验证码
    匿名函数-简单实例
    c# 如何找到项目中图片的相对路径
    MVC下 把数据库中的byte[]值保存成图片,并显示在view页面
    MVC下form表单一次上传多种类型的图片(每种类型的图片可以上传多张)
    关于Visual Studio未能加载各种Package包的解决
  • 原文地址:https://www.cnblogs.com/sunada2005/p/10847115.html
Copyright © 2020-2023  润新知