侧边栏壁纸
  • 累计撰写 793 篇文章
  • 累计创建 1 个标签
  • 累计收到 1 条评论
标签搜索

目 录CONTENT

文章目录

Proxy

Dettan
2021-04-10 / 0 评论 / 0 点赞 / 157 阅读 / 1,585 字
温馨提示:
本文最后更新于 2022-07-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
/ 后端 / JAVA / Proxy
reflect包里的一个类
以interface为基础生成一个代理类. 调用代理类会实际上调用handler类


以interface为基础 , 用interface和handler创建一个代理类, 代理类可以被转换成interface , 就可以直接调用interface的方法了,不需要实现.
调用方法之后 根据逻辑判断需要调用哪个类.


动静态代理的区别,什么场景使用?(2015-11-25)
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
动态代理是实现JDK里的InvocationHandler接口的invoke 方法,但注意的是代理的是接口,也就是你的 业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。 还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行 时,动态修改字节码达到修改类的目的。 AOP编程就是基于动态代理实现的,比如著名的Spring框架、Hibernate框架等等都是动态代理的使用例子。

Java动态代理一——动态类Proxy的使用
1.什么是动态代理?
答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
2.为什么使用动态代理?
答:因为动态代理可以对请求进行任何处理
3.使用它有哪些好处?
答:因为动态代理可以对请求进行任何处理
4.哪些地方需要动态代理 ?
答:不允许直接访问某些类;对访问要做特殊处理等
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。
其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现
以下为模拟案例,通过动态代理实现在方法调用前后向控制台输出两句字符串
写一个ArrayList的动态代理类(笔试题)
final List<String> list = new ArrayList<String>(); 

List<String> proxyInstance =  
(List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), 
																		list.getClass().getInterfaces(),  
																			new InvocationHandler() {
				@Override 
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
				return method.invoke(list, args); 
		} 
}); 

proxyInstance.add("你好"); 
System.out.println(list);

简单代理类
public class Main {
    public static void main(String[] args) {
        InvocationHandler handler = new InvocationHandler() {
						//调用
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
				//
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler
        hello.morning("Bob");
    }
}

//接口
interface Hello {
    void morning(String name);
}

在运行期动态创建一个interface实例的方法如下:
1.
定义一个InvocationHandler实例,它负责实现接口的方法调用;
2.
通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:
1.
使用的ClassLoader,通常就是接口类的ClassLoader
2.
需要实现的接口数组,至少需要传入一个接口进去;
3.
用来处理接口方法调用的InvocationHandler实例。
3.
将返回的Object强制转型为接口。
动态代理实际上是JDK在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法,把上面的动态代理改写为静态实现类大概长这样:
public class HelloDynamicProxy implements Hello {
    InvocationHandler handler;
    public HelloDynamicProxy(InvocationHandler handler) {
        this.handler = handler;
    }
    public void morning(String name) {
        handler.invoke(
           this,
           Hello.class.getMethod("morning"),
           new Object[] { name });
    }
}
其实就是JDK帮我们自动编写了一个上述类(不需要源码,可以直接生成字节码),并不存在可以直接实例化接口的黑魔法。

doBefore doAfter
给接口写一个实现类, 实例化InvocationHandler的时候传进去,然后再invoke方法里使用.
package myCode.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

public class CrimsonHandler implements InvocationHandler {
    private Object obj;

    public CrimsonHandler(Object obj) {
        super();
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        System.out.println(method.getName());
        System.out.println(method.getDeclaringClass().getName());
        //根据类名字不同做不同操作
        switch (method.getDeclaringClass().getName()) {
            case "myCode.proxy.Crimson":
                System.out.println("call out() in interface Crimson");
                break;
            case "myCode.proxy.Dettan":
                System.out.println("call out() in interface Dettan");
                break;
            case "myCode.proxy.CoolInterface":
                System.out.println("call out() in interface CoolInterface");
                System.out.println(method.invoke(obj, args));
        }

        method.getClass();//class java.lang.reflect.Method

        //获取注解,只能获取到接口上的注解
        System.out.println(Arrays.toString(method.getAnnotations()));
        System.out.println("after");
        return null;
    }
}
package myCode.proxy;

import javax.xml.ws.RequestWrapper;

public class Cool implements CoolInterface {
    @Override
    @RequestWrapper
    public String out(String a, String b) {
        return a + b;
    }
}



package myCode.proxy;

public interface CoolInterface {
    public String out(String a, String b);
}
package myCode.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

public class CrimsonHandler implements InvocationHandler {
    private Object obj;

    public CrimsonHandler(Object obj) {
        super();
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        System.out.println(method.getName());
        System.out.println(method.getDeclaringClass().getName());
        //根据类名字不同做不同操作
        switch (method.getDeclaringClass().getName()) {
            case "myCode.proxy.Crimson":
                System.out.println("call out() in interface Crimson");
                break;
            case "myCode.proxy.Dettan":
                System.out.println("call out() in interface Dettan");
                break;
            case "myCode.proxy.CoolInterface":
                System.out.println("call out() in interface CoolInterface");
                System.out.println(method.invoke(obj, args));
        }

        method.getClass();//class java.lang.reflect.Method

        //获取注解,只能获取到接口上的注解
        System.out.println(Arrays.toString(method.getAnnotations()));
        System.out.println("after");
        return null;
    }
}
0

评论区