Java 代理

一、JDK动态代理

核心接口:InvocationHandler(调用处理器),它只有一个方法 invoke 。
无论何时调用代理对象的方法,调用处理器的 invoke 方法都会被调用,并向其传递 Method 对象和原始的调用参数。

定义:
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

核心类:Proxy(代理类)
创建一个代理对象,需要使用 Proxy 类的 newProxyInstance 方法。 该方法有三个参数:一个类加载器(class loader) ,使用 null 表示使用默认的类加载器;一个 Class 对象数组,每个元素都是需要实现的接口;一个调用处理器。

定义:
public class Proxy implements java.io.Serializable

API:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派到指定的调用处理器。

static Class<?>	getProxyClass(ClassLoader loader, Class<?>... interfaces)
返回给定类加载器和接口数组的代理类的 java.lang.Class 对象。

static boolean isProxyClass(Class<?> cl)
当且仅当使用 getProxyClass 方法或 newProxyInstance 方法将指定的类动态生成为代理类时,才返回 truestatic InvocationHandler getInvocationHandler(Object proxy)
返回指定代理实例的调用处理器。

二、JDK动态代理 与 CGLIB动态代理

1、区别

  • JDK动态代理是Java标准库提供的一种代理实现方式,它主要利用Java反射机制实现。JDK动态代理要求被代理的类必须实现一个或多个接口,通过接口来定义代理对象的行为。在运行时,JDK动态代理会为被代理类生成一个实现了相同接口的代理类实例,并通过 InvocationHandler(调用处理器)来定义代理方法的具体实现。
  • CGLIB是一个强大的高性能的代码生成库,它可以在运行时扩展Java类。CGLIB动态代理通过继承被代理类来创建代理对象,因此被代理类不需要实现任何接口。CGLIB利用ASM(开源的Java字节码编辑库)修改被代理类字节码生成子类,从而实现对被代理类方法的拦截和增强。

2、代码示例

UserService接口

package site.itool;

/**
 * UserService接口
 */
public interface UserService {
    // 通过用户id打印用户姓名
    void printUserName(Long id);
}

UserService接口实现类

package site.itool;

/**
 * UserService接口实现类
 */
public class UserServiceImpl implements UserService {
    /**
     * 实现接口方法
     * @param id
     */
    @Override
    public void printUserName(Long id) {
        System.out.println("(代理对象)姓名是" + id);
    }
}

JDK动态代理

package site.itool;

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

/**
 * JDK代理类 调用处理器
 */
public class JdkProxy implements InvocationHandler {

    private Object target ; // 需要代理的目标对象

    public JdkProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK动态代理,开始!");
        Object result = method.invoke(target, args);
        System.out.println("JDK动态代理,结束!");
        return result;
    }

    /**
     * 获取代理对象方法
     * @return
     */
    private Object getJDKProxy(){
        // JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public static void main(String[] args) {
        JdkProxy jdkProxy = new JdkProxy(new UserServiceImpl());
        // 获取代理对象
        UserService user = (UserService)jdkProxy.getJDKProxy();
        user.printUserName(1L); //执行方法
    }
}

输出:
在这里插入图片描述

CGLIB动态代理

package site.itool;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * CGLIB代理类 调用处理器
 */
public class CglibProxy implements MethodInterceptor {

    private Object target ; // 需要代理的目标对象

    public CglibProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CGLIB动态代理,开始!");
        Object invoke = method.invoke(target, objects); // 方法执行,参数:target 目标对象 objects 参数数组
        System.out.println("CGLIB动态代理,结束!");
        return invoke;
    }

    /**
     * 获取代理对象方法
     * @return
     */
    public Object getCglibProxy(){
        Enhancer enhancer = new Enhancer();
        // 设置父类,因为 CGLIB 是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this); // 设置回调
        Object result = enhancer.create(); // 创建并返回代理对象
        return result;
    }

    public static void main(String[] args) {
        CglibProxy cglib = new CglibProxy(new UserServiceImpl());
        // 获取代理对象
        UserService user =  (UserService)cglib.getCglibProxy();
        user.printUserName(1L); //执行方法
    }
}

输出:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间充当中介,以便于客户端访问目标对象时,可以在不改变目标对象的情况下添加一些额外的功能,比如安全性、远程访问、缓存等。 在Java中,代理模式可以通过两种方式实现:静态代理和动态代理。静态代理需要手动编写代理类,而动态代理可以在运行时通过反射机制动态生成代理类,更加灵活。 举个例子,假设我们有一个接口`Subject`,其中定义了一些方法。我们希望在调用这些方法时,增加一些额外的日志记录功能。我们可以编写一个代理类`SubjectProxy`,在代理类中实现接口方法并调用目标对象的方法,同时在方法前后添加日志记录的代码。客户端则通过代理类访问目标对象。 静态代理示例代码如下: ```java public interface Subject { void doSomething(); } public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something."); } } public class SubjectProxy implements Subject { private Subject realSubject; public SubjectProxy(Subject realSubject) { this.realSubject = realSubject; } @Override public void doSomething() { System.out.println("Before do something."); realSubject.doSomething(); System.out.println("After do something."); } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); Subject subjectProxy = new SubjectProxy(realSubject); subjectProxy.doSomething(); } } ``` 动态代理示例代码如下: ```java public class SubjectHandler implements InvocationHandler { private Object target; public SubjectHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before " + method.getName()); Object result = method.invoke(target, args); System.out.println("After " + method.getName()); return result; } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); InvocationHandler handler = new SubjectHandler(realSubject); Subject subjectProxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); subjectProxy.doSomething(); } } ``` 无论是静态代理还是动态代理代理模式都可以在不改变目标对象的情况下,为其添加额外的功能,提高代码的可复用性和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值