jdk代理和cglib代理源代码之我见
以前值是读过一遍jdk和cglib的代理,时间长了,都忘记入口在哪里了,值是记得其中的一些重点了,今天写一篇博客,当作是笔记。和以前一样,关键代码,我会用红色标记出来。
首先,先列出我的jdk代理对象和测试代码:
package com.example.gof.proxy; /**
* 买车接口
*/
public interface BuyCard {
void buycard();
}
package com.example.gof.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class BuyCardDynamicProxy implements InvocationHandler {
private Object object; public BuyCardDynamicProxy(final Object object) {
this.object = object;
} /**
* 代理回调的方法,反编译后可以看到调用的是这段代码:super.h.invoke(this, m3, null);
* m3 = Class.forName("com.example.gof.proxy.BuyCard").getMethod("buycard", new Class[0]);
* @param proxy 代理
* @param method 代理调用的而方法
* @param args 调用的方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理,买车前");
Object res= method.invoke(object,args);
System.out.println("动态代理,洗刷刷");
return res;
}
}
package com.example.gof.proxy; import com.example.gof.proxy.impl.BuyCardImpl;
import sun.misc.ProxyGenerator; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy; public class TestBuyCardDynamicProxy {
public static void main(String[] args) throws IOException {
BuyCard buyCard = new BuyCardImpl();
BuyCard buyCardProxy = (BuyCard) Proxy.newProxyInstance(BuyCard.class.getClassLoader(),
new Class[]{BuyCard.class}, new BuyCardDynamicProxy(buyCard));
buyCardProxy.buycard();
//下面这段是用于生成字节码分析的
// byte[] classFile= ProxyGenerator.generateProxyClass("$Proxy", new Class<?>[]{BuyCard.class});
// File file=new File("D:\\java\\GoF\\src\\main\\java\\com\\example\\gof\\proxy/$Proxy.class");
// FileOutputStream os=new FileOutputStream(file);
// os.write(classFile);
// os.flush();
// os.close(); }
}
跟踪进去,查看 Proxy.newProxyInstance(BuyCard.class.getClassLoader() 这个方法,代码如下:
/**
* 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);
} /*
* 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);
} 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);
}
}
/**
* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /**
* 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
return proxyClassCache.get(loader, interfaces);
}
上面这个代码当初看了很久,怎么到proxyClassCache.get(loader, interfaces); 就已经生成了代理对象呢。后来百度下,才知道proxyClassCache9 这个对象调用构造参数时候,就生成了二进制文件,核心代码也在这里。继续往下看
/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
* 一个工厂函数,它生成、定义并返回给定类加载器和接口数组的代理类。
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override
public 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 in
int 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 package
proxyPkg = 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.
* 生成代理对象
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( //生成二进制字节码
proxyName, interfaces, accessFlags);
try {
//加载到jvm里,返回代理对象
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());
}
}
}
继续跟进生成二进制字节码的方法:ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags)
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
} Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
} return var4;
}
由上面可以看见,核心代码,就是生成了二进制字节码文件Files.write(var2, var4, new OpenOption[0]);
为什么我们看不见呢,那是因为被删除了,可以手动生成这个二进制文件(.class后缀的),也就是上面的那段测试代码的例子。
下面是二进制字节码的文件内容:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// import com.example.gof.proxy.BuyCard;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy extends Proxy implements BuyCard {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0; public $Proxy(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 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 void buycard() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} 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);
}
} static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.gof.proxy.BuyCard").getMethod("buycard");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
从上面可以看到,除了自定义的buycard() 方法外,还有toString()、equals()、hashCode() 三个方法。这三个方法是Object 的方法,每个接口、类都会从Object继承这三个方法。当调用buycard()的时候,可以看到调用的是super.h.invoke(xxx) 这样调用的。这里的h,就是我们自定义的,继承了InvocationHandler的类:BuyCardDynamicProxy。
至于invoke方式是怎么调用的,在另外一篇博客https://www.cnblogs.com/drafire/p/9637349.html 继续解析
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面看下cglib的代码解读,依然是先贴出测试代码
public class BuyCardCglibProxy implements MethodInterceptor {
private Object target; public Object getInstance(final Object target) {
this.target = target;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
} @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理前");
//这里使用的是methodProxy.invokeSuper,而不是method.invoke
//代理类调用父类的方法
Object res= methodProxy.invokeSuper(o,objects);
System.out.println("cglib动态代理后");
return res;
}
}
package com.example.gof.proxy; import com.example.gof.proxy.impl.BuyCardImpl;
import org.springframework.cglib.core.DebuggingClassWriter; public class TestBuyCardCglibProxy {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, TestBuyCardCglibProxy.class.getClass().getResource("/").getPath() );
BuyCard buyCard=new BuyCardImpl();
BuyCardCglibProxy proxy=new BuyCardCglibProxy();
BuyCardImpl impl= (BuyCardImpl)proxy.getInstance(buyCard);
impl.buycard();
}
}
关键代码在:enhancer.create() 这个方法,跟踪进去,代码如下:
public Object create() {
this.classOnly = false;
this.argumentTypes = null;
return this.createHelper();
}
private Object createHelper() {
this.preValidate();
Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}
protected Object create(Object key) {
try {
ClassLoader loader = this.getClassLoader(); //获取加载器
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
//从缓存中读取
AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) { //如果缓存没有对应的数据
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) {
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
data = new AbstractClassGenerator.ClassLoaderData(loader); //生成二进制字节码
newCache.put(loader, data);
CACHE = newCache;
}
}
} this.key = key;
Object obj = data.get(this, this.getUseCache());
//生成代理对象
return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
} catch (RuntimeException var9) {
throw var9;
} catch (Error var10) {
throw var10;
} catch (Exception var11) {
throw new CodeGenerationException(var11);
}
}
public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
} else {
this.classLoader = new WeakReference(classLoader);
Function<AbstractClassGenerator, Object> load = new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this); //核心代码
return gen.wrapCachedClass(klass);
}
};
this.generatedClasses = new LoadingCache(GET_KEY, load);
}
}
protected Class generate(AbstractClassGenerator.ClassLoaderData data) {
Object save = CURRENT.get();
CURRENT.set(this); Class var8;
try {
ClassLoader classLoader = data.getClassLoader();
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " + this.getClassName() + ". It seems that the loader has been expired from a weak reference somehow. Please file an issue at cglib's issue tracker.");
} String className;
synchronized(classLoader) {
className = this.generateClassName(data.getUniqueNamePredicate());
data.reserveName(className);
this.setClassName(className);
} Class gen;
if (this.attemptLoad) {
try {
gen = classLoader.loadClass(this.getClassName());
Class var25 = gen;
return var25;
} catch (ClassNotFoundException var20) {
;
}
} byte[] b = this.strategy.generate(this); //核心代码
className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = this.getProtectionDomain();
synchronized(classLoader) {
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
} var8 = gen;
} catch (RuntimeException var21) {
throw var21;
} catch (Error var22) {
throw var22;
} catch (Exception var23) {
throw new CodeGenerationException(var23);
} finally {
CURRENT.set(save);
} return var8;
}
//org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar!\org\springframework\cglib\core\DefaultGeneratorStrategy.class
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = this.getClassVisitor(); //从这里的源代码,可以看出,底层是使用asm包的
this.transform(cg).generateClass(cw);
return this.transform(cw.toByteArray());
}
//org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar!\org\springframework\cglib\core\KeyFactory.class public void generateClass(ClassVisitor v) {
ClassEmitter ce = new ClassEmitter(v);
Method newInstance = ReflectUtils.findNewInstance(this.keyInterface);
if (!newInstance.getReturnType().equals(Object.class)) {
throw new IllegalArgumentException("newInstance method must return Object");
} else {
Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
ce.begin_class(46, 1, this.getClassName(), KeyFactory.KEY_FACTORY, new Type[]{Type.getType(this.keyInterface)}, "<generated>");
EmitUtils.null_constructor(ce);
EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
int seed = 0;
CodeEmitter e = ce.begin_method(1, TypeUtils.parseConstructor(parameterTypes), (Type[])null);
e.load_this();
e.super_invoke_constructor();
e.load_this();
List<FieldTypeCustomizer> fieldTypeCustomizers = this.getCustomizers(FieldTypeCustomizer.class); int i;
for(i = 0; i < parameterTypes.length; ++i) {
Type parameterType = parameterTypes[i];
Type fieldType = parameterType; Iterator var11;
FieldTypeCustomizer customizer;
for(var11 = fieldTypeCustomizers.iterator(); var11.hasNext(); fieldType = customizer.getOutType(i, fieldType)) {
customizer = (FieldTypeCustomizer)var11.next();
} seed += fieldType.hashCode();
ce.declare_field(18, this.getFieldName(i), fieldType, (Object)null);
e.dup();
e.load_arg(i);
var11 = fieldTypeCustomizers.iterator(); while(var11.hasNext()) {
customizer = (FieldTypeCustomizer)var11.next();
customizer.customize(e, i, parameterType);
} e.putfield(this.getFieldName(i));
} e.return_value();
e.end_method();
e = ce.begin_method(1, KeyFactory.HASH_CODE, (Type[])null);
i = this.constant != 0 ? this.constant : KeyFactory.PRIMES[Math.abs(seed) % KeyFactory.PRIMES.length];
int hm = this.multiplier != 0 ? this.multiplier : KeyFactory.PRIMES[Math.abs(seed * 13) % KeyFactory.PRIMES.length];
e.push(i); for(int i = 0; i < parameterTypes.length; ++i) {
e.load_this();
e.getfield(this.getFieldName(i));
EmitUtils.hash_code(e, parameterTypes[i], hm, this.customizers);
} e.return_value();
e.end_method();
e = ce.begin_method(1, KeyFactory.EQUALS, (Type[])null);
Label fail = e.make_label();
e.load_arg(0);
e.instance_of_this();
e.if_jump(153, fail); int i;
for(i = 0; i < parameterTypes.length; ++i) {
e.load_this();
e.getfield(this.getFieldName(i));
e.load_arg(0);
e.checkcast_this();
e.getfield(this.getFieldName(i));
EmitUtils.not_equals(e, parameterTypes[i], fail, this.customizers);
} e.push(1);
e.return_value();
e.mark(fail);
e.push(0);
e.return_value();
e.end_method();
e = ce.begin_method(1, KeyFactory.TO_STRING, (Type[])null);
e.new_instance(Constants.TYPE_STRING_BUFFER);
e.dup();
e.invoke_constructor(Constants.TYPE_STRING_BUFFER); for(i = 0; i < parameterTypes.length; ++i) {
if (i > 0) {
e.push(", ");
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, KeyFactory.APPEND_STRING);
} e.load_this();
e.getfield(this.getFieldName(i));
EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, this.customizers);
} e.invoke_virtual(Constants.TYPE_STRING_BUFFER, KeyFactory.TO_STRING);
e.return_value();
e.end_method();
ce.end_class();
}
}
jdk代理和cglib代理源代码之我见的更多相关文章
- 总结两种动态代理jdk代理和cglib代理
动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...
- spring的AOP动态代理--JDK代理和CGLIB代理区分以及注意事项
大家都知道AOP使用了代理模式,本文主要介绍两个代理模式怎么设置以及区别,对原文一些内容进行了引用后加入了自己的理解和更深入的阐述: 一.JDK代理和CGLIB代理的底层实现区别* JDK代理只能 ...
- Java中jdk代理和cglib代理
代理模式 给某一个对象提供一个代理,并由代理对象控制对原对象的引用.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 在Java中代理模式从实 ...
- jdk代理和cglib代理
1.jdk静态代理(静态代理和动态代理) 本质:在内存中构建出接口的实现类. 缺陷:只能对实现接口的类实现动态代理, 使用cglib可以对没有实现接口的类进行动态代理. 2.cglib动态代理 ...
- 设计模式---JDK动态代理和CGLIB代理
Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public ...
- JDK动态代理和 CGLIB 代理
JDK动态代理和 CGLIB 代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期期间创建一个接口的实现类来完成对目标对象的代理. 代码示例 接口 public interface ...
- SpringAOP-JDK 动态代理和 CGLIB 代理
在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...
- 静态代理、动态代理和cglib代理
转:https://www.cnblogs.com/cenyu/p/6289209.html 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处 ...
- Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)
第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...
随机推荐
- 今儿直白的用盖房子为例,给你讲讲Java建造者模式
摘要:建造者模式(Builder Pattern)又叫生成器模式,是一种对象构建模式.它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象. 本 ...
- 哈工大 计算机系统 实验二 Datalab数据表示
所有实验文件可见github 计算机系统实验整理 由于word文件没有保存,因此如需参考此实验,请直接访问github文件
- Qt:QCustomPlot使用教程(一)——安装与配置
0.说明 本节翻译总结自:Qt Plotting Widget QCustomPlot - Setting Up 本节的内容是讲如何配置QCustomPlot,而QCustomPlot的具体用法可以看 ...
- Vue之路由的使用
零.传统路由与SPA的区别 传统开发方式下,URL改变后,就会立刻发生请求去请求整个页面,这样可能请求加载的资源过多,可能会让页面出现白屏. 在SPA(Single Page Application) ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- 【漏洞复现】Paraluni 安全事件分析及复现
Paraluni 被黑分析 前言 Paraluni (平行宇宙)是新加坡 Parallel Universe 基金会发布的一个 基于币安智能链的 DeFi 项目,更多相关内容见此处.在 2022 年 ...
- 如何恢复 iCloud 已删除文件
原文链接 问题 今天在查找之前的 C++ 笔记时,突然发现之前的资料全没了,整个 Cpp 文件夹内就只剩下了三个文件,怎么形容当时的心情呢,应该说是一下就跌倒了谷底,感觉之前的心血全白费了,有种深深的 ...
- CF258D题解
太厉害啦 首先做期望题最不能忘记的就是期望的线性性. 所以我们直接将全局逆序对对数拆成两个数其中一个比另一个大的期望(概率),设为 \(f[i][j]\),初值为 \([a_i>b_j]\). ...
- SpringDoc-OpenApi与Fastjson冲突——FastJsonHttpMessageConverter对String的默认处理
我的项目中默认是这样使用FastJsonHttpMessageConverter的: @Override public void configureMessageConverters(List< ...
- maltego的基本使用
首次使用maltego需要注册 注册网站:https://www.paterva.com/web7/buy/maltego-clients/maltego-ce.php 填写好点注册就行了 1. 打开 ...