Java基础 代理模式:静态、动态、cglib;及 spring 中 动态、cglib 两种方式的示例

Java基础 代理模式:静态、动态、cglib;及 spring 中 动态、cglib 两种方式的示例

一、代理模式介绍

代理模式,也称委托模式,是结构型设计模式之一;
代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改代理目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

1.1、静态代理与动态代理的区别主要在:
  • 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
  • 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

特点:动态代理中,代理对象不需要实现接口,但是要求被代理目标对象必须实现接口,否则不能使用动态代理。

二、Java 代理模式

java 中常用的代理模式有3种:静态代理、动态代理、cglib 动态代理

2.1、静态代理模式

使用静态代理的基本步骤:

  1. 定义公共接口;
  2. 被代理目标对象实现公共接口中的方法;
  3. 代理对象实现公共接口中的方法,通过方法调用被代理目标对象的实现方法。

缺点:

  • 冗余。由于代理对象要实现与被代理目标对象一致的接口,会产生过多的代理类。
  • 不易维护。一旦接口增加方法,被代理目标对象与代理对象都要进行修改。很难维护这么多代理类和被代理类之间的关系。

示例:
无,太简单,不想写;

2.2、动态代理模式

使用动态代理的基本步骤:

  1. 定义公共接口;
  2. 被代理目标对象实现公共接口中的方法;
  3. 定义一个实现 InvocationHandler 的代理工厂类。
  4. 通过代理工厂类的对象,创建代理对象;
  5. 代理对象调用被代理目标对象方法;

示例:

  1. 定义公共接口
package com.zk.demo.proxy;

/**
 * @ClassName: ZKDoSomethingInterface
 * @Description: TODO(simple description this class what to do. )
 * @author Vinson
 * @version 1.0
 */
public interface ZKDoSomethingInterface {

    /**
     * 做点啥
     *
     * @Title: doSomething
     * @Description: TODO(simple description this method what to do.)
     * @author Vinson
     * @date Aug 3, 2024 8:36:04 AM
     * @param param
     * @return
     * @return int
     */
    int doSomething(int param);

}
  1. 被代理目标对象实现公共接口中的方法;
package com.zk.demo.proxy;
/** 
* @ClassName: ZKDoSomethingImpl 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKDoSomethingImpl implements ZKDoSomethingInterface { // 有实现接口

    private int mP;

    public ZKDoSomethingImpl(int mP) {
        this.mP = mP;
    }

    @Override
    public int doSomething(int param) {
        System.out
                .println("[^_^:20240803-0838-001] ZKDoSomethingImpl.DoSomething 给参数 param:" + param + " 增加:" + this.mP);
        param = this.mP + param;
        return param;
    }

}
  1. 定义一个实现 InvocationHandler 处理类及工厂类。
package com.zk.demo.proxy.dynamicProxy;

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

/** 
* @ClassName: ZKInvocationHandler 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKInvocationHandler implements InvocationHandler {

    /**
     * 被代理的真实对象;
     * 
     * 必须实现一个或多个接口
     */
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("[^_^:20240803-0855-001] ZKInvocationHandler proxy:" + proxy.getClass());
        System.out.println("[^_^:20240803-0855-001] ZKInvocationHandler method:" + method.getName());
        Object rev = method.invoke(this.target, args);
        System.out.println("[^_^:20240803-0855-001] ZKInvocationHandler 执行被代理目标对象的方法结束:" + rev);
        return rev;
    }

}
package com.zk.demo.proxy.dynamicProxy;

import java.lang.reflect.Proxy;

/** 
* @ClassName: ZKDynamicProxyFactory 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKDynamicProxyFactory {

    @SuppressWarnings("unchecked")
    public <T> T getProxyInstance(Object target) {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new ZKInvocationHandler(target));
    }

}
  1. 测试
package com.zk.demo.proxy.dynamicProxy;

import org.junit.Test;
import com.zk.demo.proxy.ZKDoSomethingImpl;
import com.zk.demo.proxy.ZKDoSomethingInterface;
import junit.framework.TestCase;

/** 
* @ClassName: ZKDynamicProxyFactoryTest 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKDynamicProxyFactoryTest {

    @Test
    public void test() {
        try {
            ZKDoSomethingImpl dsImpl = new ZKDoSomethingImpl(3);
            ZKDoSomethingInterface dsProxy = null;
            int result = 0;

            ZKDynamicProxyFactory dpf = new ZKDynamicProxyFactory();
            dsProxy = dpf.getProxyInstance(dsImpl);
            System.out.println("[^_^:20240803-0839-001] 代理对象类名:" + dsProxy.getClass());
            result = dsProxy.doSomething(2);
            TestCase.assertEquals(5, result);

//            // ZKDoSomething 没实现接口,报错:java.lang.ClassCastException: class jdk.proxy2.$Proxy8 cannot be cast to class com.zk.demo.proxy.ZKDoSomething ... ...
//            ZKDoSomething ds = new ZKDoSomething(3);
//            dpf = new ZKDynamicProxyFactory();
//            ds = dpf.getProxyInstance(ds);
//            System.out.println("[^_^:20240803-0839-002] 代理对象类名:" + ds.getClass());
//            ds.doSomething(1);
//            TestCase.assertEquals(4, result);
        }
        catch(Exception e) {
            e.printStackTrace();
            TestCase.assertTrue(false);
        }
    }

}
  1. 输出结果
[^_^:20240803-0839-001] 代理对象类名:class jdk.proxy2.$Proxy7
[^_^:20240803-0855-001] ZKInvocationHandler proxy:class jdk.proxy2.$Proxy7
[^_^:20240803-0855-001] ZKInvocationHandler method:doSomething
[^_^:20240803-0838-001] ZKDoSomethingImpl.DoSomething 给参数 param:2 增加:3
[^_^:20240803-0855-001] ZKInvocationHandler 执行被代理目标对象的方法结束:5
2.3、cglib 动态代理模式

cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
他是动态代理的一种扩展,可以给未实现接口的类创建动态代理。

cglib 特点

  1. JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
    如果想代理没有实现接口的类,就可以使用cglib实现。
  2. cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。
    它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
  3. cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
    不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。
    cglib与动态代理最大的区别就是:
  4. 使用动态代理的对象必须实现一个或多个接口
  5. 使用cglib代理的对象则无需实现接口,达到代理类无侵入。

使用cglib需要引入cglib的jar包,如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

示例:

  1. 定义一个被代理目标类
package com.zk.demo.proxy;
/** 
* @ClassName: ZKDoSomething 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKDoSomething { // 没有实现接口

    private int mP;

    public ZKDoSomething() {
        this.mP = 11;
    }

    public ZKDoSomething(int mP) {
        this.mP = mP;
    }

    public int doSomething(int param) {
        System.out.println("[^_^:20240803-0920-001] ZKDoSomething.DoSomething 给参数 param:" + param + " 增加:" + this.mP);
        param = param + this.mP;
        return param;
    }

}
  1. 定义一个 MethodInterceptor 处理类及工厂类
package com.zk.demo.proxy.cglibProxy;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/** 
* @ClassName: ZKMethodInterceptor 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKMethodInterceptor implements MethodInterceptor {

    /**
     * 被代理的真实对象;
     */
    private Object target;

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

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("[^_^:20240803-0919-001] ZKMethodInterceptor proxy:  " + proxy.getClass());
        System.out.println("[^_^:20240803-0919-001] ZKMethodInterceptor target: " + target.hashCode());
        System.out.println("[^_^:20240803-0919-001] ZKMethodInterceptor method:" + method.getName());
        System.out
                .println("[^_^:20240803-0919-001] ZKMethodInterceptor methodProxy:" + methodProxy.getSuperName());
        Object rev = method.invoke(target, args);
        System.out.println("[^_^:20240803-0919-001] ZKMethodInterceptor 执行被代理目标对象的方法结束:" + rev);
        return rev;
    }

}
package com.zk.demo.proxy.cglibProxy;

import net.sf.cglib.proxy.Enhancer;

/** 
* @ClassName: ZKCglibProxyFactory 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKCglibProxyFactory {

    /**
     * 生成代理对象
     */
    @SuppressWarnings("unchecked")
    public <T> T getProxyInstance(Object target) {
        // 工具类
        Enhancer en = new Enhancer();
        // 设置父类
        en.setSuperclass(target.getClass());
        // 设置回调函数
        en.setCallback(new ZKMethodInterceptor(target));
        // 创建子类对象代理
        return (T) en.create();
    }

}
  1. 测试类
package com.zk.demo.proxy.cglibProxy;

import org.junit.Test;
import com.zk.demo.proxy.ZKDoSomething;
import junit.framework.TestCase;

/** 
* @ClassName: ZKCglibProxyFactoryTest 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKCglibProxyFactoryTest {

    /**
     * 需要在 jvm 启动时,配置参数:
     * 
     * --add-opens java.base/java.lang=ALL-UNNAMED
     * 
     * --add-opens java.base/sun.net.util=ALL-UNNAMED
     */
    @Test
    public void test() {
        try {
            ZKDoSomething ds = new ZKDoSomething(3);
            ZKDoSomething dsProxy = null;
            int result = 0;

            ZKCglibProxyFactory cpf = new ZKCglibProxyFactory();
            dsProxy = cpf.getProxyInstance(ds);
            System.out.println("[^_^:20240803-0921-001] 代理对象类名:" + ds.getClass());
            result = dsProxy.doSomething(7);
            TestCase.assertEquals(10, result);
        }
        catch(Exception e) {
            e.printStackTrace();
            TestCase.assertTrue(false);
        }
    }

}
  1. 输出
[^_^:20240803-0921-001] 代理对象类名:class com.zk.demo.proxy.ZKDoSomething
[^_^:20240803-0919-001] ZKMethodInterceptor proxy:  class com.zk.demo.proxy.ZKDoSomething$$EnhancerByCGLIB$$5aac9585
[^_^:20240803-0919-001] ZKMethodInterceptor target: 1686100174
[^_^:20240803-0919-001] ZKMethodInterceptor method:doSomething
[^_^:20240803-0919-001] ZKMethodInterceptor methodProxy:CGLIB$doSomething$0
[^_^:20240803-0920-001] ZKDoSomething.DoSomething 给参数 param:7 增加:3
[^_^:20240803-0919-001] ZKMethodInterceptor 执行被代理目标对象的方法结束:10

注意:升级到 java 17 以上后,会报错

java.lang.ExceptionInInitializerError
	at com.zk.demo.proxy.cglibProxy.ZKCglibProxyFactory.getProxyInstance(ZKCglibProxyFactory.java:59)
	at com.zk.demo.proxy.cglibProxy.ZKCglibProxyTest.test(ZKCglibProxyTest.java:38)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:757)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @673ba40c
	at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:464)
	at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:339)
	at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96)
	at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94)
	at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
	at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
	at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)
	at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)
	at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)
	at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:174)
	at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:153)
	at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)
	... 26 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @673ba40c
	at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:315)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:203)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:197)
	at net.sf.cglib.core.ReflectUtils$1.run(ReflectUtils.java:61)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:571)
	at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:52)
	at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:243)
	at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332)
	... 38 more

解决方法:

  • 添加 jvm 启动参数:
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED

请添加图片描述

三、spring: java 方式动态代理、cglib 方式动态代理 的两种方式的示例

3.1、java 方式

接口与实现类,沿用前面的定义

  1. 定义 InvocationHandler 处理类及工厂类
package com.zk.demo.proxy.springProxy;

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.InvocationHandler;

/**
 * @ClassName: ZKSpringInvocationHandler
 * @Description: TODO(simple description this class what to do. )
 * @author Vinson
 * @version 1.0
 */
public class ZKSpringInvocationHandler implements InvocationHandler {

    /**
     * spring java 方式:被代理的真实对象;
     * 
     * 必须实现一个或多个接口;效果与 java.lang.reflect.InvocationHandler 相同;
     * 
     */
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("[^_^:20240804-0002-001] spring.ZKSpringInvocationHandler proxy:" + proxy.getClass());
        System.out.println("[^_^:20240804-0002-001] spring.ZKSpringInvocationHandler method:" + method.getName());
        Object rev = method.invoke(this.target, args);
        System.out.println("[^_^:20240803-2240-001] spring.ZKSpringInvocationHandler 执行被代理目标对象的方法结束:" + rev);
        return rev;
    }

}
package com.zk.demo.proxy.springProxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.Proxy;

/** 
* @ClassName: ZKSpringAopProxyFactory 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKSpringAopProxyFactory {

    /**
     * java 方式动态代理:被代理目标对象,需要实现接口
     */
    @SuppressWarnings("unchecked")
    public <T> T getProxyInstanceInvocation(Object target) {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new ZKSpringInvocationHandler(target));
    }
    
    /**
     * cglib 方式动态代理:被代理目标对象,可不实现接口
     */
    @SuppressWarnings("unchecked")
    public <T> T getProxyInstanceInterceptor(Object target) {
        Enhancer e = new Enhancer();
        e.setSuperclass(target.getClass());
        e.setCallback(new ZKSpringMethodInterceptor(target));
        return (T) e.create();
    }

}
  1. 测试类: testInvocation 方法
package com.zk.demo.proxy.springProxy;

import org.junit.Test;

import com.zk.demo.proxy.ZKDoSomething;
import com.zk.demo.proxy.ZKDoSomethingImpl;
import com.zk.demo.proxy.ZKDoSomethingInterface;

import junit.framework.TestCase;

/** 
* @ClassName: ZKSpringAopProxyFactoryTest 
* @Description: TODO(simple description this class what to do. ) 
* @author Vinson 
* @version 1.0 
*/
public class ZKSpringAopProxyFactoryTest {

    @Test
    public void testInvocation() {
        try {
            ZKDoSomethingImpl dsImpl = new ZKDoSomethingImpl(3);
            ZKDoSomethingInterface dsProxyInterface = null;
            int result = 0;
            ZKSpringAopProxyFactory springAopProxyFactory = new ZKSpringAopProxyFactory();

            dsProxyInterface = springAopProxyFactory.getProxyInstanceInvocation(dsImpl);
            System.out.println("[^_^:20240803-2344-001] 代理对象类名:" + dsProxyInterface.getClass());
            result = dsProxyInterface.doSomething(1);
            TestCase.assertEquals(4, result);

//            // java.lang.ClassCastException: class org.springframework.cglib.proxy.Proxy$ProxyImpl$$EnhancerByCGLIB$$805bc317
//            dsProxy = springAopProxyFactory.getProxyInstanceInvocation(ds);
//            System.out.println("[^_^:20240803-2344-002] 代理对象类名:" + dsProxy.getClass());
//            result = dsProxy.doSomething(2);
//            TestCase.assertEquals(5, result);
        }
        catch(Exception e) {
            e.printStackTrace();
            TestCase.assertTrue(false);
        }
    }

    @Test
    public void testInterceptor() {
        try {
            ZKDoSomething ds = new ZKDoSomething(3);
            ZKDoSomething dsProxy = null;
            int result = 0;
            ZKSpringAopProxyFactory springAopProxyFactory = new ZKSpringAopProxyFactory();

            dsProxy = springAopProxyFactory.getProxyInstanceInterceptor(ds);
            System.out.println("[^_^:20240803-2344-001] 代理对象类名:" + dsProxy.getClass());
            result = dsProxy.doSomething(3);
            TestCase.assertEquals(6, result);

        }
        catch(Exception e) {
            e.printStackTrace();
            TestCase.assertTrue(false);
        }
    }

}
  1. 输出
[^_^:20240803-2344-001] 代理对象类名:class org.springframework.cglib.proxy.Proxy$ProxyImpl$$EnhancerByCGLIB$$89892ccc
[^_^:20240804-0002-001] spring.ZKSpringInvocationHandler proxy:class org.springframework.cglib.proxy.Proxy$ProxyImpl$$EnhancerByCGLIB$$89892ccc
[^_^:20240804-0002-001] spring.ZKSpringInvocationHandler method:doSomething
[^_^:20240803-0838-001] ZKDoSomethingImpl.DoSomething 给参数 param:1 增加:3
[^_^:20240803-2240-001] spring.ZKSpringInvocationHandler 执行被代理目标对象的方法结束:4
3.2、cglib 方式

实现类,沿用前面的定义

  1. 定义 MethodInterceptor 处理类及工厂类;
package com.zk.demo.proxy.springProxy;

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * 
 * @ClassName: ZKSpringMethodInterceptor
 * @Description: TODO(simple description this class what to do. )
 * @author Vinson
 * @version 1.0
 */
public class ZKSpringMethodInterceptor implements MethodInterceptor {

    /**
     * spring cglib 方式:被代理的真实对象;
     */
    private Object target;

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

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("[^_^:20240803-2240-001] ZKSpringMethodInterceptor proxy:" + proxy.getClass());
//        System.out.println("[^_^:20240803-2240-001] ZKSpringMethodInterceptor methodProxy:" + proxy.getClass());
        System.out.println("[^_^:20240803-2240-001] ZKSpringMethodInterceptor method:" + method.getName());
        System.out
                .println("[^_^:20240803-2240-001] ZKSpringMethodInterceptor methodProxy:" + methodProxy.getSuperName());
        Object rev = method.invoke(this.target, args);
//        Object rev = methodProxy.invokeSuper(this.target, args);
        System.out.println("[^_^:20240803-2240-001] ZKSpringMethodInterceptor 执行被代理目标对象的方法结束:" + rev);
        return rev;

    }

}
工厂类沿用 ZKSpringAopProxyFactory
  1. 测试类: 沿用ZKSpringAopProxyFactoryTest testInterceptor 方法
  2. 输出
[^_^:20240803-2344-001] 代理对象类名:class com.zk.demo.proxy.ZKDoSomething$$EnhancerByCGLIB$$50a2c1ca
[^_^:20240803-2240-001] ZKSpringMethodInterceptor proxy:class com.zk.demo.proxy.ZKDoSomething$$EnhancerByCGLIB$$50a2c1ca
[^_^:20240803-2240-001] ZKSpringMethodInterceptor method:doSomething
[^_^:20240803-2240-001] ZKSpringMethodInterceptor methodProxy:CGLIB$doSomething$0
[^_^:20240803-0920-001] ZKDoSomething.DoSomething 给参数 param:3 增加:3
[^_^:20240803-2240-001] ZKSpringMethodInterceptor 执行被代理目标对象的方法结束:6

spring中cglib方式与2.3章中的cglib方式不同,spring中cglib方式在java17及以上不需要配置jvm启动参数:
–add-opens java.base/java.lang=ALL-UNNAMED
–add-opens java.base/sun.net.util=ALL-UNNAMED

参考:
https://juejin.cn/post/6844903978342301709
https://segmentfault.com/a/1190000011291179


若有凝问或错误,请指出,我好及时改正,让我们一起进步!
email : binary_space@126.com
qq : 103 586 2795
敲门砖: 代码谱写人生

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

征客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值