Spring 中的 ProxyFactory 创建代理对象

server/2024/11/24 20:52:35/

一、jdk 动态代理 和 cglib动态代理 简单介绍 

        1.jdk动态代理

java">public interface AService {public String serviceA(String param);public String serviceAA(String param);
}
java">public interface BService {public String serviceB(String param);public String serviceBB(String param);
}
java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class JdkCustomInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {if(method.equals(AService.class.getMethod("serviceA" , String.class))){// 在这里可以写 当我们把代理当作 AService 的实现子类,调用 serviceA 方法时// 我们要执行的代码,这里我们姑且就简单打印,并返回一个值System.out.println("JdkCustomInvocationHandler 开始处理 com.fll.start.dynamic_proxy.jdk.AService.serviceA 方法");return "JdkCustomInvocationHandler 处理 com.fll.start.dynamic_proxy.jdk.BService.serviceA 的结果";}else if(method.equals(BService.class.getMethod("serviceB", String.class))){// 在这里可以写 当我们把代理当作 BService 的实现子类,调用 serviceB 方法时// 我们要执行的代码,这里我们姑且就简单打印,并返回一个值System.out.println("JdkCustomInvocationHandler 开始处理 com.fll.start.dynamic_proxy.jdk.BService.serviceB 方法");return "JdkCustomInvocationHandler 处理 com.fll.start.dynamic_proxy.jdk.BService.serviceB 的结果";}else {return "暂时对该方法没有处理逻辑";}}
}

这里总结下jdk动态代理的特点:
        1.可以不需要实现类,直接对接口进行代理
        2.创建代理对象时返回的类型时Object,但是可以将其强转为任何一个它所代理的接口类型
因为生成的代理对象是它所代理的所有接口的实现类
        3.当我们将代理对象强转为它所代理的接口类型进行方法调用时,所有的调用都会回调到InvocationHandler 对象的 invoke 方法,在回调 invoke 方法的参数中有我们调用的方法对象 Method method,和调用时所传递的所有参数Object[] objects,Object o就是代理对象本身
        4.关于这几个参数的注意点
                1.不能在 invoke 方法中将代理对象强转为它所代理的某一个接口,然后调用其方法,这          样会形成递归调用,造成栈内存溢出
                2.如果没有所代理的接口的真正实现类,不可以通过反射的方法调用该方法,因为通过            反射的方式,Method.invoke() 方法进行调用时,需要传递真正实现了该接口的实现类的一个          对象,这里的Object o对象虽然也是接口的实现类的对象,但是不能传递 o ,如果过传递                o,还是相当于调用了代理对象的方法,也会形成递归调用。
                3.要想让代理对象调用不同的方法时,分别执行我们想要的逻辑,只能在 invoke 方法的          回调中通过判断 Method method 对象的不同,执行不同业务逻辑
        5.这样的的代理方式没啥实际意义,只是把对所有接口方法的调用全部回调到了 InvocationHandler.invoke() 方法中,在invoke中进行分别实现,会造成代码冗长杂乱

 接下来常规用法

java">public class AServiceImpl implements AService{@Overridepublic String serviceA(String param){System.out.println("AServiceImpl 开始执行 serviceA,param=" + param);return "AServiceImpl.serviceA 处理的结果";}@Overridepublic String serviceAA(String param) {System.out.println("AServiceImpl 开始执行 serviceAA,param=" + param);return "AServiceImpl.serviceAA 处理的结果";}
}
java">public class BServiceImpl implements BService{@Overridepublic String serviceB(String param){System.out.println("BServiceImpl 开始执行 serviceB,param=" + param);return "BServiceImpl.serviceB 处理的结果";}@Overridepublic String serviceBB(String param) {System.out.println("BServiceImpl 开始执行 serviceBB,param=" + param);return "BServiceImpl.serviceBB 处理的结果";}
}
java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class JdkCustomInvocationHandler1 implements InvocationHandler {private AService aService;private BService bService;public JdkCustomInvocationHandler1(AService aService , BService bService){this.aService = aService;this.bService = bService;}@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {if(method.equals(AService.class.getMethod("serviceA" , String.class))){System.out.println(String.format("执行%s前置加强逻辑" , aService.getClass() +"."+ method.getName()));Object retVal = method.invoke(this.aService , objects);System.out.println(String.format("执行%s后置加强逻辑" , aService.getClass() +"."+ method.getName()));return retVal + "(也可以被代理对象再加工)";}else if(method.equals(BService.class.getMethod("serviceB", String.class))){System.out.println(String.format("执行%s前置加强逻辑" , bService.getClass() +"."+ method.getName()));Object retVal = method.invoke(this.bService , objects);System.out.println(String.format("执行%s后置加强逻辑" , bService.getClass() +"."+ method.getName()));return retVal + "(也可以被代理对象再加工)";}else {return "暂时对该方法没有处理逻辑";}}
}
java">public class JdkDynamicProxyTest1 {public static void main(String[] args) throws IOException {ClassLoader classLoader = JdkDynamicProxyTest1.class.getClassLoader();Class[] interfaces = {AService.class, BService.class};AService aService = new AServiceImpl();BService bService = new BServiceImpl();JdkCustomInvocationHandler1 jdkCustomInvocationHandler= new JdkCustomInvocationHandler1(aService , bService);AService aServiceProxy = (AService) Proxy.newProxyInstance(classLoader, interfaces, jdkCustomInvocationHandler);String test = aServiceProxy.serviceA("AService");System.out.println(test);System.out.println();BService bServiceProxy = (BService) Proxy.newProxyInstance(classLoader , interfaces , jdkCustomInvocationHandler);String test1 = bServiceProxy.serviceB("BService");System.out.println(test1);}}运行结果:
执行class com.fll.start.dynamic_proxy.jdk.AServiceImpl.serviceA前置加强逻辑
AServiceImpl 开始执行 serviceA,param=AService
执行class com.fll.start.dynamic_proxy.jdk.AServiceImpl.serviceA后置加强逻辑
AServiceImpl.serviceA 处理的结果(也可以被代理对象再加工)执行class com.fll.start.dynamic_proxy.jdk.BServiceImpl.serviceB前置加强逻辑
BServiceImpl 开始执行 serviceB,param=BService
执行class com.fll.start.dynamic_proxy.jdk.BServiceImpl.serviceB后置加强逻辑
BServiceImpl.serviceB 处理的结果(也可以被代理对象再加工)

          这次的特点:
                1.所代理的接口本来就有自己的实现类
                2.调用所代理的接口的方法时,最终都会在 InvocationHandler.invoke() 方法中通过反射           的方式调用到接口实现类对象的对应方法上,只不过我们可以在调用实现类方法之前或者之           后执行额外的逻辑,进行加强,也可以对实现类返回的结果进行再加工

        其实这种方式才是代理模式要达到的真正目的,本来就有实现好的功能,而且代码运行稳定,或者说一个黑盒子,我们只知道其功能和参数,这些情况下,我们想要对原本的功能或者黑盒子进行加强,但是又不想修改原来代码逻辑,所以就可以通过代理,在原来的功能之上 ,进行额外的加强处理

 通过jdk源码,看看代理对象是如何创建的
java.lang.reflect.Proxy#newProxyInstance

java">/*** Returns an instance of a proxy class for the specified interfaces* that dispatches method invocations to the specified invocation* handler.** <p>{@code Proxy.newProxyInstance} throws* {@code IllegalArgumentException} for the same reasons that* {@code Proxy.getProxyClass} does.** @param   loader the class loader to define the proxy class* @param   interfaces the list of interfaces for the proxy class*          to implement* @param   h the invocation handler to dispatch method invocations to* @return  a proxy instance with the specified invocation handler of a*          proxy class that is defined by the specified class loader*          and that implements the specified interfaces* @throws  IllegalArgumentException if any of the restrictions on the*          parameters that may be passed to {@code getProxyClass}*          are violated* @throws  SecurityException if a security manager, <em>s</em>, is present*          and any of the following conditions is met:*          <ul>*          <li> the given {@code loader} is {@code null} and*               the caller's class loader is not {@code null} and the*               invocation of {@link SecurityManager#checkPermission*               s.checkPermission} with*               {@code RuntimePermission("getClassLoader")} permission*               denies access;</li>*          <li> for each proxy interface, {@code intf},*               the caller's class loader is not the same as or an*               ancestor of the class loader for {@code intf} and*               invocation of {@link SecurityManager#checkPackageAccess*               s.checkPackageAccess()} denies access to {@code intf};</li>*          <li> any of the given proxy interfaces is non-public and the*               caller class is not in the same {@linkplain Package runtime package}*               as the non-public interface and the invocation of*               {@link SecurityManager#checkPermission s.checkPermission} with*               {@code ReflectPermission("newProxyInPackage.{package name}")}*               permission denies access.</li>*          </ul>* @throws  NullPointerException if the {@code interfaces} array*          argument or any of its elements are {@code null}, or*          if the invocation handler, {@code h}, is*          {@code null}*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/* * 生成代理类的 Class 对象* Look up or generate the designated proxy class.*/Class<?> cl = getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}// 这里的private static final Class<?>[] constructorParams =// {InvocationHandler.class };// 通过代理类的 Class 对象获取参数为 InvocationHandler 对象的构造器对象final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}// 通过代理类构造器对象创一个 代理类的对象return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}
}

java.lang.reflect.Proxy#getProxyClass0 

java">/*** Generate a proxy class.  Must call the checkProxyAccess method* to perform permission checks before calling this.*/
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactory// 如果被指定的类加载器定义好的,实现了指定接口的代理类 Class 对象已经存在了// 那就简单的返回缓存中的备份,相反如果不存在,就得通过ProxyClassFactory创建// 代理类的 Class 对象,并放入缓存中return proxyClassCache.get(loader, interfaces);
}

 java.lang.reflect.WeakCache#get

java">/*** Look-up the value through the cache. This always evaluates the* {@code subKeyFactory} function and optionally evaluates* {@code valueFactory} function if there is no entry in the cache for given* pair of (key, subKey) or the entry has already been cleared.** @param key       possibly null key* @param parameter parameter used together with key to create sub-key and*                  value (should not be null)* @return the cached value (never null)* @throws NullPointerException if {@code parameter} passed in or*                              {@code sub-key} calculated by*                              {@code subKeyFactory} or {@code value}*                              calculated by {@code valueFactory} is null.*/
public V get(K key, P parameter) {Objects.requireNonNull(parameter);expungeStaleEntries();Object cacheKey = CacheKey.valueOf(key, refQueue);// lazily install the 2nd level valuesMap for the particular cacheKeyConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);if (valuesMap == null) {ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());if (oldValuesMap != null) {valuesMap = oldValuesMap;}}//// create subKey and retrieve the possible Supplier<V> stored by that// subKey from valuesMap// 生成代理类Class对象的主要逻辑在 subKeyFactory.apply(key, parameter)Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));Supplier<V> supplier = valuesMap.get(subKey);Factory factory = null;while (true) {if (supplier != null) {// supplier might be a Factory or a CacheValue<V> instanceV value = supplier.get();if (value != null) {return value;}}// else no supplier in cache// or a supplier that returned null (could be a cleared CacheValue// or a Factory that wasn't successful in installing the CacheValue)// lazily construct a Factoryif (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);}if (supplier == null) {supplier = valuesMap.putIfAbsent(subKey, factory);if (supplier == null) {// successfully installed Factorysupplier = factory;}// else retry with winning supplier} else {if (valuesMap.replace(subKey, supplier, factory)) {// successfully replaced// cleared CacheEntry / unsuccessful Factory// with our Factorysupplier = factory;} else {// retry with current suppliersupplier = valuesMap.get(subKey);}}}
}

 java.lang.reflect.Proxy.ProxyClassFactory#apply

java">/*** A factory function that generates, defines and returns the proxy class given* the ClassLoader and array of interfaces.*/
private static final class ProxyClassFactoryimplements BiFunction<ClassLoader, Class<?>[], Class<?>>
{// prefix for all proxy class namesprivate static final String proxyClassNamePrefix = "$Proxy";// next number to use for generation of unique proxy class namesprivate static final AtomicLong nextUniqueNumber = new AtomicLong();@Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);for (Class<?> intf : interfaces) {/** Verify that the class loader resolves the name of this* interface to the same Class object.*/Class<?> interfaceClass = null;try {interfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {throw new IllegalArgumentException(intf + " is not visible from class loader");}/** Verify that the Class object actually represents an* interface.*/if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}/** Verify that this interface is not a duplicate.*/if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}}String proxyPkg = null;     // package to define proxy class inint accessFlags = Modifier.PUBLIC | Modifier.FINAL;/** Record the package of a non-public proxy interface so that the* proxy class will be defined in the same package.  Verify that* all non-public proxy interfaces are in the same package.*/for (Class<?> intf : interfaces) {int flags = intf.getModifiers();if (!Modifier.isPublic(flags)) {accessFlags = Modifier.FINAL;String name = intf.getName();int n = name.lastIndexOf('.');String pkg = ((n == -1) ? "" : name.substring(0, n + 1));if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException("non-public interfaces from different packages");}}}if (proxyPkg == null) {// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}/** Choose a name for the proxy class to generate.*/long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** Generate the specified proxy class.* 生成代理类,我们看到生成代理类Class对象需要两部* 1.生成一个字节数组,其实等价于我们通过.class文件创建Class对象的时候,把.class文件            * 加载进内存,放到一个字节数组中* 2.通过 defineClass0() 方法把字节数组解析为一个Class对象*/byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);try {return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}}
}

 我们看到可以通过以下代码生成一个等价于.class文件的字节数组,那我们把生成的这个字节数组输出到一个文件,是不是就相当于得到了这个代理类的 .class 文件了

java">byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
java">import sun.misc.ProxyGenerator;import java.io.IOException;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;public class ProxyGeneratorTest {public static void main(String[] args) throws IOException {ClassLoader classLoader = JdkDynamicProxyTest1.class.getClassLoader();Class[] interfaces = {AService.class, BService.class};AService aService = new AServiceImpl();BService bService = new BServiceImpl();JdkCustomInvocationHandler1 jdkCustomInvocationHandler= new JdkCustomInvocationHandler1(aService , bService);Object proxyInstance = Proxy.newProxyInstance(classLoader, interfaces, jdkCustomInvocationHandler);byte[] bytes = ProxyGenerator.generateProxyClass(proxyInstance.getClass().getSimpleName(), interfaces);Files.write(Paths.get("D:/springboot-demo/study-spring/src/main/java/com/fll/start/dynamic_proxy/jdk/" + proxyInstance.getClass().getSimpleName() + ".class") , bytes);}}

 以下是使用idea将生成的.class文件反编译之后得到的源码

java">import com.fll.start.dynamic_proxy.jdk.AService;
import com.fll.start.dynamic_proxy.jdk.BService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements AService, BService {private static Method m1;private static Method m4;private static Method m2;private static Method m6;private static Method m3;private static Method m0;private static Method m5;public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String serviceA(String var1) throws  {try {return (String)super.h.invoke(this, m4, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String toString() throws  {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String serviceBB(String var1) throws  {try {return (String)super.h.invoke(this, m6, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String serviceAA(String var1) throws  {try {return (String)super.h.invoke(this, m3, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final int hashCode() throws  {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String serviceB(String var1) throws  {try {return (String)super.h.invoke(this, m5, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m4 = Class.forName("com.fll.start.dynamic_proxy.jdk.AService").getMethod("serviceA", Class.forName("java.lang.String"));m2 = Class.forName("java.lang.Object").getMethod("toString");m6 = Class.forName("com.fll.start.dynamic_proxy.jdk.BService").getMethod("serviceBB", Class.forName("java.lang.String"));m3 = Class.forName("com.fll.start.dynamic_proxy.jdk.AService").getMethod("serviceAA", Class.forName("java.lang.String"));m0 = Class.forName("java.lang.Object").getMethod("hashCode");m5 = Class.forName("com.fll.start.dynamic_proxy.jdk.BService").getMethod("serviceB", Class.forName("java.lang.String"));} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

这里注意最好用 jdk1.8,在jdk11 中,这个方法就不是public了,测试调用的话比较麻烦 

可以看到这里的代理类 除了实现了 我们要代理的接口 AService, BService之外还结成了java.lang.reflect.Proxy,我们使用代理类的构造器创建代理对象时,所传的 构造器参数InvocationHandler 就是通过 super(InvocationHandler) 传到了java.lang.reflect.Proxy

        2.cglib动态代理

java">public class CustomCglibMethodInterceptor<T> implements MethodInterceptor {private T target;public CustomCglibMethodInterceptor(T target){this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println(String.format("执行%s前置加强逻辑" , target.getClass() +"."+ method.getName()));Object invoke = method.invoke(target, objects);methodProxy.invoke(target , objects);System.out.println(String.format("执行%s后置加强逻辑" , target.getClass() +"."+ method.getName()));return invoke + "(也可以被代理对象再加工)";}}
java">public class CglibDynamicProxyTest {public static void main(String[] args) {AService aService = new AServiceImpl();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(aService.getClass());
//        enhancer.setSuperclass(AService.class);enhancer.setCallback(new CustomCglibMethodInterceptor(aService));AService aServiceProxy = (AService) enhancer.create();String s = aServiceProxy.serviceA("test-serviceA");System.out.println(s);}}运行结果:
执行class com.fll.start.dynamic_proxy.AServiceImpl.serviceA前置加强逻辑
AServiceImpl 开始执行 serviceA,param=test-serviceA
AServiceImpl 开始执行 serviceA,param=test-serviceA
执行class com.fll.start.dynamic_proxy.AServiceImpl.serviceA后置加强逻辑
AServiceImpl.serviceA 处理的结果(也可以被代理对象再加工)

        总结一下 cglib 动态代理的特点:

                1. cglib既能代理接口,又能代理实现类
                2. 如果代理的时接口,那么生成的代理类就会实现该接口,如果代理的时实现类,那么         生成代理类就会继承该类,由于java的类之间只支持单继承,所以一个 cglib 代理类只能代理         一个接口,或者代理一个实现类
                3. 在 cglib 的MethodInterceptor 实现类中,调用目标对象的有两种方法                                            method.invoke(target, objects);
                methodProxy.invoke(target , objects);

那么 cglib 的原理是什么呢,我们能不能也想上面反编译jdk动态代理类字节码一样,反编译一下cglib的代理类的字节码呢,我自己想了个办法还是成功反编译了
org.springframework.cglib.core.AbstractClassGenerator#generate

java">protected Class generate(ClassLoaderData data) {Class gen;Object save = CURRENT.get();CURRENT.set(this);try {ClassLoader classLoader = data.getClassLoader();if (classLoader == null) {throw new IllegalStateException("ClassLoader is null while trying to define class " +getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +"Please file an issue at cglib's issue tracker.");}synchronized (classLoader) {String name = generateClassName(data.getUniqueNamePredicate());data.reserveName(name);this.setClassName(name);}if (attemptLoad) {try {gen = classLoader.loadClass(getClassName());return gen;}catch (ClassNotFoundException e) {// ignore}}byte[] b = strategy.generate(this);String className = ClassNameReader.getClassName(new ClassReader(b));ProtectionDomain protectionDomain = getProtectionDomain();synchronized (classLoader) { // just in case// SPRING PATCH BEGINgen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);// SPRING PATCH END}return gen;}catch (RuntimeException | Error ex) {throw ex;}catch (Exception ex) {throw new CodeGenerationException(ex);}finally {CURRENT.set(save);}}

java">Files.write(Paths.get("D:/springboot-demo/study-spring/src/main/java/com/fll/start/dynamic_proxy/cglib/" + "AServiceImpl$$EnhancerByCGLIB$$bfa5b612.class") , b) 

我们可以看到Files 和 Paths 都爆红,可以想正常写代码那样导入包就行了

解决了报错之后,直接点击右下角的 Evaluate 就可以了,然后刷新一下你输出的包,就会出现你输出的 .class 文件

 使用 idea 打开就可以看到反编译后的代理类源码

java">package com.fll.start.dynamic_proxy;import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;public class AServiceImpl$$EnhancerByCGLIB$$bfa5b612 extends AServiceImpl implements Factory {private boolean CGLIB$BOUND;public static Object CGLIB$FACTORY_DATA;private static final ThreadLocal CGLIB$THREAD_CALLBACKS;private static final Callback[] CGLIB$STATIC_CALLBACKS;private MethodInterceptor CGLIB$CALLBACK_0;private static Object CGLIB$CALLBACK_FILTER;private static final Method CGLIB$serviceA$0$Method;private static final MethodProxy CGLIB$serviceA$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$serviceAA$1$Method;private static final MethodProxy CGLIB$serviceAA$1$Proxy;private static final Method CGLIB$equals$2$Method;private static final MethodProxy CGLIB$equals$2$Proxy;private static final Method CGLIB$toString$3$Method;private static final MethodProxy CGLIB$toString$3$Proxy;private static final Method CGLIB$hashCode$4$Method;private static final MethodProxy CGLIB$hashCode$4$Proxy;private static final Method CGLIB$clone$5$Method;private static final MethodProxy CGLIB$clone$5$Proxy;static void CGLIB$STATICHOOK1() {CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class var0 = Class.forName("com.fll.start.dynamic_proxy.AServiceImpl$$EnhancerByCGLIB$$bfa5b612");Class var1;Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());CGLIB$equals$2$Method = var10000[0];CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");CGLIB$toString$3$Method = var10000[1];CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");CGLIB$hashCode$4$Method = var10000[2];CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");CGLIB$clone$5$Method = var10000[3];CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");var10000 = ReflectUtils.findMethods(new String[]{"serviceA", "(Ljava/lang/String;)Ljava/lang/String;", "serviceAA", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("com.fll.start.dynamic_proxy.AServiceImpl")).getDeclaredMethods());CGLIB$serviceA$0$Method = var10000[0];CGLIB$serviceA$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "serviceA", "CGLIB$serviceA$0");CGLIB$serviceAA$1$Method = var10000[1];CGLIB$serviceAA$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "serviceAA", "CGLIB$serviceAA$1");}final String CGLIB$serviceA$0(String var1) {return super.serviceA(var1);}public final String serviceA(String var1) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? (String)var10000.intercept(this, CGLIB$serviceA$0$Method, new Object[]{var1}, CGLIB$serviceA$0$Proxy) : super.serviceA(var1);}final String CGLIB$serviceAA$1(String var1) {return super.serviceAA(var1);}public final String serviceAA(String var1) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? (String)var10000.intercept(this, CGLIB$serviceAA$1$Method, new Object[]{var1}, CGLIB$serviceAA$1$Proxy) : super.serviceAA(var1);}final boolean CGLIB$equals$2(Object var1) {return super.equals(var1);}public final boolean equals(Object var1) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);return var2 == null ? false : (Boolean)var2;} else {return super.equals(var1);}}final String CGLIB$toString$3() {return super.toString();}public final String toString() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();}final int CGLIB$hashCode$4() {return super.hashCode();}public final int hashCode() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);return var1 == null ? 0 : ((Number)var1).intValue();} else {return super.hashCode();}}final Object CGLIB$clone$5() throws CloneNotSupportedException {return super.clone();}protected final Object clone() throws CloneNotSupportedException {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();}public static MethodProxy CGLIB$findMethodProxy(Signature var0) {String var10000 = var0.toString();switch(var10000.hashCode()) {case -2021511251:if (var10000.equals("serviceA(Ljava/lang/String;)Ljava/lang/String;")) {return CGLIB$serviceA$0$Proxy;}break;case -508378822:if (var10000.equals("clone()Ljava/lang/Object;")) {return CGLIB$clone$5$Proxy;}break;case 386645590:if (var10000.equals("serviceAA(Ljava/lang/String;)Ljava/lang/String;")) {return CGLIB$serviceAA$1$Proxy;}break;case 1826985398:if (var10000.equals("equals(Ljava/lang/Object;)Z")) {return CGLIB$equals$2$Proxy;}break;case 1913648695:if (var10000.equals("toString()Ljava/lang/String;")) {return CGLIB$toString$3$Proxy;}break;case 1984935277:if (var10000.equals("hashCode()I")) {return CGLIB$hashCode$4$Proxy;}}return null;}public AServiceImpl$$EnhancerByCGLIB$$bfa5b612() {CGLIB$BIND_CALLBACKS(this);}public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {CGLIB$STATIC_CALLBACKS = var0;}private static final void CGLIB$BIND_CALLBACKS(Object var0) {AServiceImpl$$EnhancerByCGLIB$$bfa5b612 var1 = (AServiceImpl$$EnhancerByCGLIB$$bfa5b612)var0;if (!var1.CGLIB$BOUND) {var1.CGLIB$BOUND = true;Object var10000 = CGLIB$THREAD_CALLBACKS.get();if (var10000 == null) {var10000 = CGLIB$STATIC_CALLBACKS;if (var10000 == null) {return;}}var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];}}public Object newInstance(Callback[] var1) {CGLIB$SET_THREAD_CALLBACKS(var1);AServiceImpl$$EnhancerByCGLIB$$bfa5b612 var10000 = new AServiceImpl$$EnhancerByCGLIB$$bfa5b612();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Callback var1) {CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});AServiceImpl$$EnhancerByCGLIB$$bfa5b612 var10000 = new AServiceImpl$$EnhancerByCGLIB$$bfa5b612();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {CGLIB$SET_THREAD_CALLBACKS(var3);AServiceImpl$$EnhancerByCGLIB$$bfa5b612 var10000 = new AServiceImpl$$EnhancerByCGLIB$$bfa5b612;switch(var1.length) {case 0:var10000.<init>();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;default:throw new IllegalArgumentException("Constructor not found");}}public Callback getCallback(int var1) {CGLIB$BIND_CALLBACKS(this);MethodInterceptor var10000;switch(var1) {case 0:var10000 = this.CGLIB$CALLBACK_0;break;default:var10000 = null;}return var10000;}public void setCallback(int var1, Callback var2) {switch(var1) {case 0:this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;default:}}public Callback[] getCallbacks() {CGLIB$BIND_CALLBACKS(this);return new Callback[]{this.CGLIB$CALLBACK_0};}public void setCallbacks(Callback[] var1) {this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];}static {CGLIB$STATICHOOK1();}
}

 可以看到 cglib 的代理类源码 和 jdk 动态代理的 代理类源码 实现原理都差不多,都是先把被代理的类或者被代理接口所有的方法的 Method 对象取出来作为代理类的成员变量,当调用代理类的对应方法时,就在成员变量中找到对应的 Method 对象 和 和传进来的参数,一起调用一个 回调方法,这个回调方法是我们自己实现的,所以我们可以在回调方法中按照自己的想法来实现

二、Spring中的 三个重要的概念 Advice  Advisor  Advised

        1.Advice

        2.Advisor

        3.Advised

三、ProxyFactory 类的继承结构,以及每一层中实现的功能

四、AopProxyFactory的默认实现类DefaultAopProxyFactory的介绍

五、Spring 中的 InvocationHandler --- JdkDynamicAopProxy

六、AdvisedSupport 中 getInterceptorsAndDynamicInterceptionAdvice 详解

七、AdvisorChainFactory 的默认实现类 DefaultAdvisorChainFactory

八、AdvisorAdapterRegistry 的 默认实现类 DefaultAdvisorAdapterRegistry

九、简单介绍 Interceptor

十、详细介绍 MethodInterceptor 

十一、如何通过 MethodInterceptor 几个实现类实现 Advice 的顺序调用

AdvisorChainFactory 的默认实现类 DefaultAdvisorChainFactory

http://www.ppmy.cn/server/144637.html

相关文章

C语言-11-18笔记

1.C语言数据类型 类型存储大小值范围char1 字节-128 到 127 或 0 到 255unsigned char1 字节0 到 255signed char1 字节-128 到 127int2 或 4 字节-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647unsigned int2 或 4 字节0 到 65,535 或 0 到 4,294,967,295short2 字节…

Android 基于Camera2 API进行摄像机图像预览

前言 近期博主准备编写一个基于Android Camera2的图像采集并编码为h.264的应用&#xff0c;准备分为三个阶段来完成&#xff0c;第一阶段实现Camera2的摄像机预览&#xff0c;第二阶段完成基于MediaCodec H.264编码&#xff0c;第三阶段完成基于MediaCodec H.264解码,针对不同…

python探测脚本

编写一个脚本test_ip.py实现指定参数的远程主机网络探测 python test_ip.py 192.168.0.10 192.168.0.100 针对192.168.0.10~192.168.0.100范围内所有主机进行网络探测 import sys import time获取命令行参数&#xff1a;python test_ip.py 192.168.0.10 192.168.0.100 initial_…

纯HTMLCSS实现3D旋转地球

效果演示 这段 HTML 和 CSS 代码创建了一个带有动画效果的星空背景&#xff0c;其中包含闪烁的星星和一个旋转的地球图案。 HTML <div class"section-banner"><div id"star-1"><div class"curved-corner-star"><div id…

网页F12:缓存的使用(设值、取值、删除)

一、设置值 例如&#xff1a;设置一个key为name&#xff0c;value为Jack的值 1、在控制台输入代码 localStorage.setItem(name,Jack) 2、查看缓存值 二、取值 1、在控制台输入代码 取出key为name的值 localStorage.getItem(name) 三、删除 删除指定key的值 1、在控制台输…

03. 运算符

一、运算符与表达式 运算符 就是对字面量或者变量进行操作的符号&#xff1b;表达式 是指用运算符把字面量或者变量连接起来&#xff0c;符合 Python 语法的式子。不同运算符连接的表达式体现的是不同类型的表达式&#xff1b;Python 中的运算符主要包括 算术运算符、赋值运算符…

TDK推出第二代用于汽车安全应用的6轴IMU

近日&#xff0c;据外媒报道&#xff0c;TDK株式会社推出用于汽车安全应用的第二代6轴 IMU&#xff0c;即为TDK InvenSense SmartAutomotive MEMS传感器系列增加了IAM-20685HP和IAM-20689&#xff0c;为决策算法提供可靠的运动数据&#xff0c;并实时准确地检测车辆动态。这对于…

如何下载链接为blob类型的视频,video 标签 src:blob 链接转下载MP4

文章目录 前言这种链接是如何生成的&#xff1f;原理分析 第一步&#xff0c;找到源地址1.在想下载的视频网页&#xff0c;按f12打开开发人员工具。找到video标签&#xff0c;锁定src属性2.确认src源为blob&#xff1a;样式&#xff0c;转到网络&#xff08;network&#xff09…