• 关于java动态代理模式


    1. 动态代理


    • 动态代理就是通过代理类是代理类与相关接口不直接发生联系,而在运行期(Runtime)实现动态关联。
    • 动态代理主要用到java.lang.reflect包中的两个类,InvocationHandler接口和Proxy类。
    • 动态代理相较于静态代理最大的不同就是:动态代理的代理类不需要手动生成,该代理类是在运行期间动态生成的,这个动态生成的代理类已经实现代理对象的相关接口(Interface)。在生成代理类的同时,必须提供一个handler,这个handler有InvocationHandler提供,同时用来接管实际的工作。

    2. InvocationHandler接口


    (1)接口声明:
    public interface InvocationHandler
    • 每一个动态代理类都必须实现InvocationHandler接口,InvocationHandler是代理实例(代理的真实对象),的调用处理程序实现的接口,当通过代理实例调用一个方法的时候,该方法的调用就会指派到它调用处理程序(InvocationHandler接口)的 invoke 方法。
    (2)invoke方法声明:
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    参数意义:Object proxy: 指代所代理的真实对象,也就是真实对象的代理
             Method method: 指代所调用的真实对象的某个方法的Method对象
             Object[] args: 指代所代理的真实对象某个方法的参数

    3. Proxy类


    (1)类声明:
    public class Proxy extends Object implements Serializable
    • Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类(JDK).
    • Proxy类根据已经提供的相关接口和被代理的类就可以利用反射机制得到实现的方法,根据Proxy类的newProxyInstance(...)方法生成代理类。
    (2)newProxyInstance方法声明:
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
                                   throws IllegalArgumentException
    参数意义:
       ClassLoader loader:   类加载器,就是把动态生成的代理类的字节码文件加载到JVM虚拟机中,一般使用被代理类的类加载器
       Class<?>[] interfaces:为代理对象提供的接口,就是被代理类实现的接口
       InvocationHandler h:  当代理对象调用方法的时候关联到InvocationHandler对象上,也就是前面说的*调用处理程序*(有待更深理解)

    4.动态代理模式实现


    package com.manu;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    public class TestTrendsProxy {
    	public static void main(String[] args) {
    		Subject man = new Man();
    		Proxy p = new Proxy(man);
    		//通过java.lang.reflect.newProxyInstance(...)方法获得真实对象的代理对象
    		Subject subject = (Subject)java.lang.reflect.Proxy.newProxyInstance(man.getClass().getClassLoader(), man.getClass().getInterfaces(), p);
    		//通过代理对象调用真实对象相关接口中实现的方法,这个时候就会跳转到这个代理对象所关联的handler的invoke()方法去执行
    		subject.shopping();	
    		//获得真实对象的代理对象所对应的Class对象的名称,用字符串表示
    		System.out.println(subject.getClass().getName());
    		//调用处理程序的表示
    		InvocationHandler handler = java.lang.reflect.Proxy.getInvocationHandler(subject);
    		System.out.println(handler);
    	}
    }
    //被代理人和代理人要执行的动作
    interface Subject{
    	void shopping();
    }
    //被代理类
    class Man implements Subject{
    	private String name="Tom";
    	public void shopping() {
    		System.out.println(name+"要去买东西...");
    	}
    }
    //代理类
    class Proxy implements InvocationHandler{
    	private Object target;//要代理的真实对象
    	public Proxy(Subject target){
    		this.target = target;
    	}
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		System.out.println("proxy:"+proxy.getClass().getName());
    		System.out.println("购买之前的评估工作...");
    		method.invoke(target, args);
    		System.out.println("购买之后的满意度调查...");
    		return null;
    	}	
    }

    下面是运行结果:

    运行结果:
    proxy:com.manu.$Proxy0
    购买之前的评估工作...
    Tom要去买东西...
    购买之后的满意度调查...
    com.manu.$Proxy0
    com.manu.Proxy@6bc7c054

    运行结果中出现的$Proxy0是subject.getClass().getName())得到的,返回的是类的名称,这是在运行时动态创建的,命名方式貌似是$Proxy+编号构成。整个代理过程主要体现在一个handler上。

    任尔几路来,我自一路去...

    如果选择关注微信公众号:jzman-blog,一起交流学习!


  • 相关阅读:
    python网络爬虫——scrapy核心组件介绍、请求传参、下载中间件
    python网络爬虫——Scrapy全站数据爬取【手动请求发送】及post请求的发送
    python网络爬虫——scrapy框架持久化存储
    php常见排序
    php实现快速排序
    mysql读写分离 主从同步
    php预定义字符
    本地Navicat连不上Linux虚拟机MySQL数据库问题
    php yii 命令
    yii 定义场景
  • 原文地址:https://www.cnblogs.com/jzmanu/p/10284793.html
Copyright © 2020-2023  润新知