java-动态代理

代理模式

代理模式是Java中常用的设计模式,主要由公共接口、被代理类和代理类等三部分组成,代理类持有被代理类的实类,代为执行具体的类方法。其中代理类与被代理类有同样的接口。

代理类与被代理类之间通常会存在关联关系,一个代理类的对象与一个被代理类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用被代理类对象的方法来提供特定的服务。

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起中介的作用。

代理模式UML

  • Subject:抽象主题角色,抽象主题类可以是抽象类,也可以是接口,是一个最普通的业务类型定义,无特殊要求。
  • RealSubject:具体主题角色,也叫被委托对象,被代理角色。是业务逻辑的具体执行者
  • Proxy:代理主题角色,也叫委托类、代理类。它把所有抽象主题类定义的方法给具体主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后工作。

代理模式

根据加载被代理类的时机不同,将代理分为静态代理和动态代理。

静态代理,程序运行之前就已经存在的编译好的代理类

动态代理,程序运行时动态生成,根据java的反射机制动态生成

静态代理

静态代理:在代码编译时就确定了具体的被代理类。由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。

代码案例

//IMacSeller.java
public interface IMacSeller{
  void buy()
}


//USAMacSeller.java
public class USAMacSeller implements IMacSeller{
  @Override
  public void buy(){
    System.out.println("buy a macbook from USA")
  }
}


//HongkongMacSeller.java
public class HongkongMacSeller implements IMacSeller{
  IMacSeller seller =new USAMacSeller();
  @Override
  public void buy(){
    seller.buy();
    System.out.println("buy a macbook from Hongkong");
  }
}


//Client.java
public class Client{
  public static void main(String[] args){
    System.out.println("Proxy main");
    IMacSeller seller = new HongkongMacSeller();
    seller.buy();
  }
}

JAVA动态代理

什么是动态代理

使用jdk的反射机制,创建对象的能力,创建的是代理类的的对象.而不用我们创建类文件,不用写java文件。什么叫动态?在程序执行时,调用jdk提供的方法才能创建代理类的对象

动态代理介绍

  1. 动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
  2. 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
  3. 动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理

动态代理的实现(2种方式)

  1. jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
  2. cglib动态代理(了解): cglib是第三方的工具库,创建代理对象
    1. cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法,实现功能的修改。
    2. 因为cglib是继承,重写方法,所以要求目标类不能是final的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,比如mybatis,spring框架中都有使用。

JDK动态代理主要方法说明

jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandlerMethodProxy

1. 反射 (理解反射的method.invoke方法)

Method类,表示方法。类中的方法,通过反射 Method可以执行某个方法

method.invoke() 反射调用方法

2. jdk动态代理的实现

创建动态代理类会使用到java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

反射包 java.lang.reflect ,里面有3个类:InvocationHandler,Method,Proxy

java.lang.reflect.Proxy

java.lang.reflect.Proxy主要用于生成动态代理类Class、创建代理类实例,该类实现了java.io.Serializable接口。

创建代理类:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

java.lang.reflect.Proxy类主要方法如下:

package java.lang.reflect;

import java.lang.reflect.InvocationHandler;

/**
 * Creator: yz
 * Date: 2020/1/15
 */
public class Proxy implements java.io.Serializable {

  // 省去成员变量和部分类方法...

    /**
     * 获取动态代理处理类对象
     *
     * @param proxy 返回调用处理程序的代理实例
     * @return 代理实例的调用处理程序
     * @throws IllegalArgumentException 如果参数不是一个代理实例
     */
    public static InvocationHandler getInvocationHandler(Object proxy)
            throws IllegalArgumentException {
        ...
    }

    /**
     * 创建动态代理类实例
     *
     * @param loader     指定动态代理类的类加载器
     * @param interfaces 指定动态代理类的类需要实现的接口数组
     * @param h          动态代理处理类
     * @return 返回动态代理生成的代理类实例
     * @throws IllegalArgumentException 不正确的参数异常
     */
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
            throws IllegalArgumentException {
        ...
    }

    /**
     * 创建动态代理类
     *
     * @param loader     定义代理类的类加载器
     * @param interfaces 代理类要实现的接口列表
     * @return 用指定的类加载器定义的代理类,它可以实现指定的接口
     */
    public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {
        ...
    }

    /**
     * 检测某个类是否是动态代理类
     *
     * @param cl 要测试的类
     * @return 如该类为代理类,则为 true,否则为 false
     */
    public static boolean isProxyClass(Class<?> cl) {
        return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }

    /**
     * 向指定的类加载器中定义一个类对象
     *
     * @param loader 类加载器
     * @param name   类名
     * @param b      类字节码
     * @param off    截取开始位置
     * @param len    截取长度
     * @return JVM创建的类Class对象
     */
    private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

}

java中要创建一个代理对象,必须调用Proxy类的静态方法newProInstance,该方法原型如下:

Object Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler) throws IllegalArgumentException
  
  
//loader,表示类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是java安全模型的一部分。
//interfaces,它就是被代理类对象的共有的接口
//handler,表示调用处理器,它必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作

java.lang.reflect.InvocationHandler

InvocationHandler 接口只有一个方法invoke,定义了代理对象在执行真实对象的方法时所希望执行的动作

invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在invoke中

代理类完成的功能:

1、调用目标方法,执行目标方法的功能

2、功能增强,在目标方法调用时,增加功能

方法原型:

Object invoke(Object proxy,Method method,Object[] args) throws Throwable
  // proxy,jdk创建的代理对象,无需赋值
  // method,目标类中的方法,jdk提供的method对象
  // args,目标类中方法的参数,jdk提供

InvocationHandler接口:表示你的代理要干什么

怎么用:

1.创建类实现接口InvocationHandler

2.重写invoke()方法,把原来静态代理中代理类要完成的功能写到这里

3. JDK动态代理案例

定义接口ImiSeller

package com.tyut.dynamic;

public interface ImiSeller {
    void buy();

}

实现接口的目标实现类Mistore

package com.tyut.dynamic;

public class Mistore implements ImiSeller {
    @Override
    public void buy() {
        System.out.println("通过小米商店买了一部小米手机");
    }
}

定义代理类实现的具体增强类MyHandler,重写invoke方法,代理类具体执行的方法

package com.tyut.dynamic;

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

public class MyHandler  implements InvocationHandler {
    Object proxyTarget;

    public MyHandler(Object proxyTarget) {
        this.proxyTarget = proxyTarget;
        
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(proxyTarget,args); //个人理解,通过反射调用目标类方法,这里的invoke是反射,上面的invoke是invocationHandler接口的方法
        System.out.println("增强代理方式实现");
        return null;
    }
}

创建代理对象并执行代理方法

package com.tyut.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MyApp {
    public static void main(String[] args) {
        // 目标类
        ImiSeller sell = new  Mistore();
      
        //实现InvocationHandle接口中的invoke方法,并将被代理的实例对象传入,相当于之前的代理类,谁使用它,它就返回谁的对象,
        InvocationHandler myhandler = new MyHandler(sell);
        
      	// 动态生成代理类对象
        // 指定动态代理类的类加载器 sell.getClass().getClassLoader()
        // 定义动态代理类 实现的接口 sell.getClass().getInterfaces()
        // 动态代理处理类
        ImiSeller proxy = (ImiSeller) Proxy.newProxyInstance(sell.getClass().getClassLoader(), sell.getClass().getInterfaces(),myhandler);
        
      //使用生成的代理类,调用invoke中定义的方法
        proxy.buy();
    }
}

通过动态代理就可以动态生成代理类,实现接口InvocationHandler的类(这个实现InvocationHandler的类相当于定义好被代理类的相关操作),最后然后通过Proxy类的newProxyInstance方法来生成动态代理类!

posted @ 2022-03-09 10:40  lalalaxiaoyuren  阅读(668)  评论(0编辑  收藏  举报