代理模式:一个对象提供一个替身,以控制对这个对象的访问。
即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。-
代理模式有不同的形式,主要有三种静态代理、动态代理(JDK 代理、接口代理)和CGLIB 代理(可以在内存动态的创建对象,而不需要实现接口,他是属于动态代理的范畴)。
1.2.静态代理 1.2.1.基本介绍静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。
定义一个接口
public interface Teacher {
void teach();
}
定义一个实现类
public class JTeacher implements Teacher {
// 实现具体的内容
public void teach() {
System.out.println("Jak正在讲解代理模式");
}
}
定义代理类
// 静态代理的方式
public class TeacherProxy implements Teacher{
// 定义引用
private Teacher teacher;
//具体的目标对象传入进来
public TeacherProxy(Teacher teacher) {
this.teacher = teacher;
}
public void teach() {
System.out.println("begin...");
// 调用目标对象的方法
teacher.teach();
System.out.println("end...");
}
}
使用代理前结果:
使用代理后结果:
成功通过静态代理,对目标方法进行了增强
上述是实现了一个接口,假如有多个接口呢?
代理类就会做很大的修改,很不容易扩展维护
再定义一个接口
public interface School {
void work();
}
实现此接口
public class JTeacher implements Teacher, School {
// 实现具体的内容
public void teach() {
System.out.println("Jak正在讲解代理模式");
}
// 在工作
public void work() {
System.out.println("Jak在清华工作");
}
}
代理类进行修改
/ 静态代理的方式
public class TeacherProxy implements Teacher, School{
// 定义引用
private Teacher teacher;
private School school;
//具体的目标对象传入进来
public TeacherProxy(Teacher teacher, School school) {
this.teacher = teacher;
this.school = school;
}
public void teach() {
System.out.println("begin...");
// 调用目标对象的方法
teacher.teach();
System.out.println("end...");
}
public void work() {
System.out.println("begin...");
school.work();
System.out.println("end...");
}
}
jdk代理是基于接口的代理,所以被代理的对象必须是有接口实现的类,代理创建时通过Proxy.newProxyInstance
实现的,这个方法有三个参数:
//指定要使用的类加载器
ClassLoader loader,
//被代理的类所实现的接口,增强接口的方法
Class[] interfaces,
//方法处理器,会拦截所有方法,然后执行增强参数。
InvocationHandler inoker
定义一个类
public interface Teacher {
void teach();
}
定义一个实现类
public class JTeacher implements Teacher {
// 实现具体的内容
public void teach() {
System.out.println("Jak正在讲解代理模式");
}
}
定义一个生成代理的代理工厂
// 生成代理对象的工厂类
public class JdkProxyFactory implements InvocationHandler {
// 定义目标对象引用
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 提供方法,生成代理对象的
public Object getProxy() {
// 使用JDK的API方法
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("begin...");
// 让目标对象的方法去执行,使用反射方式
// 执行method
Object result = method.invoke(target, args);
System.out.println("end...");
return result;
}
}
测试结果:
再看一下动态代理,实现多个接口的情况
public class JTeacher implements Teacher, School {
// 实现具体的内容
public void teach() {
System.out.println("Jak正在讲解代理模式");
}
// 在工作
public void work() {
System.out.println("Jak在清华工作");
}
}
代理工厂不需要任何改动
// 生成代理对象的工厂类
public class JdkProxyFactory implements InvocationHandler {
// 定义目标对象引用
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 提供方法,生成代理对象的
public Object getProxy() {
// 使用JDK的API方法
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("begin...");
// 让目标对象的方法去执行,使用反射方式
// 执行method
Object result = method.invoke(target, args);
System.out.println("end...");
return result;
}
}
测试结果
此时,我们的代理工厂代码就不用动,测试的时候,只需要School来接收,然后,调用相应的方法即可实现增强功能。这样以来,对我们程序的扩展就非常方便。
1.4 Cglib动态代理public interface TargetInterface {
String sayHello(String name);
String sayThanks(String name);
}
public class TargetInterfaceImpl implements TargetInterface {
public String sayHello(String name) {
return "Hello, " + name;
}
public String sayThanks(String name) {
return "Thanks, " + name;
}
}
**
* TargetProxy类还不是一个真正的代理类,它是代理类的一部分
*/
public class TargetProxy implements MethodInterceptor {
// 获取真正的代理类
public T getProxy(Class clazz) {
// 继承目标类,覆盖目标类的方法
// 字节码增强的一个类
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(clazz);
// 设置回调类,继承了MethodInterceptor,而它又继承了CallBack
enhancer.setCallback(this);
// 创建代理类
return (T) enhancer.create();
}
/**
* @param obj CGLIB 生成的代理对象
* @param method 被代理对象方法
* @param args 方法入参
* @param proxy 方法代理
*/
// 即可以拦截sayHello,也可以拦截sayThanks
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method.getName() + "服务限流.......");
// 调用目标方法(代理类是子类,目标类是父类)
return proxy.invokeSuper(obj, args);
/**
// 获取一个接口的代理,那么需要在此对接口进行实现
String hello = "Hello, " + args;
return hello;
*/
}
}
public class Main {
public static void main(String[] args) {
// 通过参数设置,把动态代理生成的字节码.class文件输出到D盘
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/");
TargetProxy targetProxy = new TargetProxy();
// 拿到目标类的代理类
TargetInterfaceImpl targetInterface = targetProxy.getProxy(TargetInterfaceImpl.class);
System.out.println(targetInterface.sayHello("jak"));
System.out.println(targetInterface.sayThanks("jak"));
}
}
完成了对目标方法的增强
二、源码解析 2.1 JDK动态代理源码核心点:从源码-->编译好一个字节码文件.class-->类加载器变成对象-->构造器变成实例对象
类的加载机制、类加载详解
// 提供方法,生成代理对象的
public Object getProxy() {
// 使用JDK的API方法
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
对于上面这个方法,调用后就直接是一个对象了,对应流程图中,相当于已经到了实例对象User对象那步了,但是,前面的那些流程我们都没有做
肯定是Java替我们做了这些工作,那么它是怎么做的呢?
如果对反射创建对象不清楚的可以先看下这个:反射创建对象
// newProxyInstance
@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对象,相当于到了流程图的第二步了
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() {
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);
}
}
// getProxyClass0
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
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 cacheKey
ConcurrentMap valuesMap = map.get(cacheKey);
// 第一次取肯定是没有的,进入判断
if (valuesMap == null) {
ConcurrentMap oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier stored by that
// subKey from valuesMap
// 如果没有,就在此处生成
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue instance
V 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 Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
// ProxyClassFactory in Proxy.apply
@Override
public Class apply(ClassLoader loader, Class[] interfaces) {
Map 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数组中,正常情况,编译后生成一个.class文件存到磁盘
// 这就是流程图的第一步
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// native方法,通过类加载器,加载到内存,帮你生成Class对象
// 流程图的第二步
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
public static byte[] generateProxyClass(final String name,
Class[] interfaces,
int accessFlags)
{
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
// 这里是生成 JDK 动态代理 Class File 的逻辑,暂时可以忽略。
final byte[] classFile = gen.generateClassFile();
// 如果 saveGeneratedFiles 变量为 true,把生成的 Class 文件写入到当前项目根目录下
if (saveGeneratedFiles) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Void run() {
try {
int i = name.lastIndexOf('.');
Path path;
if (i > 0) {
Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
Files.createDirectories(dir);
path = dir.resolve(name.substring(i+1, name.length()) + ".class");
} else {
path = Paths.get(name + ".class");
}
Files.write(path, classFile);
return null;
} catch (IOException e) {
throw new InternalError(
"I/O exception saving generated file: " + e);
}
}
});
}
return classFile;
}
讲到这你可能会说,还是不懂,刚才只是讲了你怎么生成的字节码文件,怎么生成的Class对象,但是它怎么执行的呢?
刚才说到,生成的.class字节码保存到了byte数组中,那么我们能不能把它保存成文件,看看到底做了什么呢?
如果可以的话,我们就可以通过生成的文件,把它反编译回来,看看它生成的源码长什么样
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
// $Proxy0这个代理类继承了Proxy实现了Teacher和School接口
public final class $Proxy0 extends Proxy implements Teacher, School {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
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);
}
}
// 重写了work方法
public final void work() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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);
}
}
// 重写了teach方法
public final void teach() 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"));
m4 = Class.forName("com.best.staticProxy.School").getMethod("work");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.best.staticProxy.Teacher").getMethod("teach");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
参考JDK动态代理
2.2 CGLIB动态代理源码CGLIB动态代理实现原理、参考CGLIB动态代理
上文中的是通过 enhancer.create
方法调用获取的代理对象,以此为入口深入探究一下 CGLIB 动态代理的实现原理。
// Enhancer#create
// 生成代理类名称是用到了 SOURCE 字段
private static final Source SOURCE = new Source(Enhancer.class.getName());
public Enhancer() {
super(SOURCE);
}
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
// Enhancer#createHelper
private Object createHelper() {
preValidate();
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
// 调用父类create方法
Object result = super.create(key);
return result;
}
// AbstractClassGenerator.create
protected Object create(Object key) {
try {
ClassLoader loader = getClassLoader();
Map cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map newCache = new WeakHashMap(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
// 也就是ClassLoaderData的get方法
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
}
catch (RuntimeException | Error ex) {
throw ex;
}
catch (Exception ex) {
throw new CodeGenerationException(ex);
}
}
接下来我们关注 ClassLoaderData
的 get
方法的逻辑。
// 代理类字节码的默认生成策略
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
// 代理类的默认命名策略
private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;
protected Class generate(ClassLoaderData data) {
Class gen;
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) {
// 1. 生成代理类的类名
String name = generateClassName(data.getUniqueNamePredicate());
data.reserveName(name);
this.setClassName(name);
}
// 2. 生成代理类字节码的二进制数组
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
return gen;
}
private String generateClassName(Predicate nameTestPredicate) {
return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate);
}
CGLIB 通过 DefaultNamingPolicy
类中的 getClassName
方法获取到代理类的名称,逻辑如下所示
/**
* 为代理类选择一个类名
* @param prefix 被代理类的全路径名称,比如这里的 com.wilimm.proxy.cglib.Service
* @param source 生成代理类的全限定名(如 "net.sf.cglib.Enhance", "net.sf.cglib.reflect.FastClass")
* @param key 表示参数状态的关键对象; 要使缓存正常工作,相等的键应该生成相同的生成类名。默认策略将 key.hashCode() 合并到类名中。
* @param names 如果给定的类名已经在同一个 ClassLoader 中使用,则返回 true 的谓词。
* @return 全限定的代理类类名
*/
public String getClassName(String prefix, String source, Object key, Predicate names) {
String base =
prefix + "$$" +
source.substring(source.lastIndexOf('.') + 1) +
getTag() + "$$" +
Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode());
String attempt = base;
int index = 2;
// 检测生成的代理类名是否已经生成,如果已经生成,则需要添加后缀
while (names.evaluate(attempt))
attempt = base + "_" + index++;
return attempt;
}
protected String getTag() {
return "ByCGLIB";
}
我们简单看一下 DefaultGeneratorStrategy
类中的 generate
方法,这是真正生成代理类的地方。
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = getClassVisitor();
// 生成代理类的地方,代码逻辑过于复杂,暂时忽略
transform(cg).generateClass(cw);
return transform(cw.toByteArray());
}
最后,我们重点关注下 DebuggingClassWriter
类中的 toByteArray
方法,在这个方法中我们可以看到如何保存 CGLIB 代理类 Class 到文件中。
public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation";
private static String debugLocation;
static {
debugLocation = System.getProperty(DEBUG_LOCATION_PROPERTY);
if (debugLocation != null) {
System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");
}
}
public byte[] toByteArray() {
return (byte[]) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
// 如果 DebuggingClassWriter.DEBUG_LOCATION_PROPERTY 系统属性被设置,则输出代理类到指定目录
if (debugLocation != null) {
String dirs = className.replace('.', File.separatorChar);
try {
new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
File file = new File(new File(debugLocation), dirs + ".class");
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
try {
out.write(b);
} finally {
out.close();
}
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
return b;
}
});
}
}
CGLIB 生成的代理类剖析
由上文可知,把 DebuggingClassWriter.DEBUG_LOCATION_PROPERTY
(也就是 cglib.debugLocation
)系统属性设置为当前项目的根目录,即可保存 CGLIB 生成的代理类到当前项目根目录下。
运行前文中 Client
的 main
方法,即可在当D盘看到 CGLIB 生成的代理类 Class 文件,如下图所示。
TargetInterfaceImpl$$EnhancerByCGLIB$$49b0b14d.class就是CGLIB生成的代理类,它继承了Service
public class TargetInterfaceImpl$$EnhancerByCGLIB$$49b0b14d extends TargetInterfaceImpl implements Factory {
private MethodInterceptor CGLIB$CALLBACK_0; // 拦截器
private static final Method CGLIB$publicMethod$0$Method; // 被代理方法
private static final MethodProxy CGLIB$publicMethod$0$Proxy; // 代理方法
static void CGLIB$STATICHOOK1() {
// 代理类
Class var0 = Class.forName("com.wilimm.proxy.cglib.Service$$EnhancerByCGLIB$$bdabbd96");
// 被代理类
Class var1;
CGLIB$publicMethod$0$Method = ReflectUtils.findMethods(new String[]{"publicMethod", "()V"}, (var1 = Class.forName("com.wilimm.proxy.cglib.Service")).getDeclaredMethods())[0];
CGLIB$publicMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "publicMethod", "CGLIB$publicMethod$0");
}
// 代理方法(methodProxy.invokeSuper会调用)
final String CGLIB$sayThanks$0(String var1) {
return super.sayThanks(var1);
}
// 被代理方法(methodProxy.invoke会调用,这就是为什么在拦截器中调用methodProxy.invoke会死循环,一直在调用拦截器)
public final String sayThanks(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayThanks$0$Method, new Object[]{var1}, CGLIB$sayThanks$0$Proxy) : super.sayThanks(var1);
}
final String CGLIB$sayHello$1(String var1) {
return super.sayHello(var1);
}
public final String sayHello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayHello$1$Method, new Object[]{var1}, CGLIB$sayHello$1$Proxy) : super.sayHello(var1);
}
}
MethodProxy
类非常关键,我们分析一下它的内部逻辑。
public class MethodProxy {
private Signature sig1;
private Signature sig2;
private CreateInfo createInfo;
private final Object initLock = new Object();
private volatile FastClassInfo fastClassInfo;
/**
*
* @param c1 被代理对象 Class
* @param c2 CGLIB 代理对象 Class
* @param desc 入参类型
* @param name1 有拦截器逻辑的方法名 publicMethod
* @param name2 直接调用父类方法的方法名 CGLIB$publicMethod$0
* @return
*/
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
private void init() {
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
// 1. 生成被代理类 FastClass,在这里是 Service$$FastClassByCGLIB$$fdf36b96
fci.f1 = helper(ci, ci.c1);
// 2. 生成代理类 FastClass,在这里是 Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2
fci.f2 = helper(ci, ci.c2);
// 3. 得到被代理类 FastClass 中的 publicMethod 方法签名
fci.i1 = fci.f1.getIndex(sig1);
// 4. 得到代理类 FastClass 中的 CGLIB$publicMethod$0 方法签名
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
private static class FastClassInfo {
FastClass f1; //被代理类 FastClass,在这里是 Service$$FastClassByCGLIB$$fdf36b96
FastClass f2; //代理类 FastClass,在这里是 Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2
int i1; // 被代理类 FastClass 中的 publicMethod方法签名(index)
int i2; // 代理类 FastClass 中的 CGLIB$publicMethod$0 的方法签名
}
/**
* 在相同类型的不同对象上调用原始方法。如果传入的是代理对象,则调用的是 CGLIB 代理类重写的方法
* @param obj 方法调用的对象,如果使用 MethodInterceptor 的 intercept 方法的第一个参数,将导致递归
* @param args 参数列表
*/
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
// 调用 Service$$FastClassByCGLIB$$fdf36b96 类中的 publicMethod 方法
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
/**
* 在代理对象上调用父类的原始方法
* @param obj CGLIB 生成的代理对象
* @param args 参数列表
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
// 调用 Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2 类中的 CGLIB$publicMethod$0 方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
package com.wilimm.proxy.cglib;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
public class Service$$FastClassByCGLIB$$fdf36b96 extends FastClass {
public Service$$FastClassByCGLIB$$fdf36b96(Class var1) {
super(var1);
}
// 根据方法签名,获取到 FastClass 中的方法 index 值
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -560613858:
if (var10000.equals("finalMethod()V")) {
return 1;
}
break;
case -433379701:
if (var10000.equals("publicMethod()V")) {
return 0;
}
break;
}
return -1;
}
/**
* 调用 FastClass 中的方法
* @param var1 方法 index 值
* @param var2 方法所在的类的对象
* @param var3 参数列表
*/
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
// 强制转换 Object 为 Service 类型,从而可以直接调用 Service 中定义的方法
Service var10000 = (Service)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.publicMethod();
return null;
case 1:
var10000.finalMethod();
return null;
case 2:
return new Boolean(var10000.equals(var3[0]));
case 3:
return var10000.toString();
case 4:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
package com.wilimm.proxy.cglib;
import com.wilimm.proxy.cglib.Service..EnhancerByCGLIB..bdabbd96;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;
public class Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2 extends FastClass {
public Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2(Class var1) {
super(var1);
}
// 根据方法签名,获取到 FastClass 中的方法 index 值
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -560613858:
if (var10000.equals("finalMethod()V")) {
return 21;
}
break;
case -433379701:
if (var10000.equals("publicMethod()V")) {
return 9;
}
break;
case 920107676:
if (var10000.equals("CGLIB$publicMethod$0()V")) {
return 16;
}
break;
return -1;
}
/**
* 调用 FastClass 中的方法
* @param var1 方法 index 值
* @param var2 方法所在的类的对象
* @param var3 参数列表
*/
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
// 强制转换 Object 为 bdabbd96 代理类类型,从而可以直接调用 代理类中定义的方法
bdabbd96 var10000 = (bdabbd96)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.clone();
case 4:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 5:
return var10000.newInstance((Callback[])var3[0]);
case 6:
return var10000.newInstance((Callback)var3[0]);
case 7:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 8:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 9:
var10000.publicMethod();
return null;
case 10:
bdabbd96.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 11:
bdabbd96.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 12:
return var10000.getCallbacks();
case 13:
return var10000.getCallback(((Number)var3[0]).intValue());
case 14:
return bdabbd96.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
bdabbd96.CGLIB$STATICHOOK1();
return null;
case 16:
var10000.CGLIB$publicMethod$0();
return null;
case 17:
return var10000.CGLIB$clone$4();
case 18:
return new Integer(var10000.CGLIB$hashCode$3());
case 19:
return var10000.CGLIB$toString$2();
case 20:
return new Boolean(var10000.CGLIB$equals$1(var3[0]));
case 21:
var10000.finalMethod();
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
CGLib 动态代理原理是什么?
CGLIB原理: 动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。
在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
CGLIB底层∶使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
三、CGLIB 和 JDK 动态代理区别JDK动态代理是利用反射机制生成一个实现代理接口的类(这个类看不见摸不着,在jvm内存中有这个类),在调用具体方法前调用InvokeHandler来处理。
核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。
CGLIB动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。
1、如果目标对象实现了接口,默认情况下Spring会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,Spring也可以强制使用CGLIB实现AOP
3、如果目标对象没有实现接口,必须采用CGLIB实现动态代理,当然Spring可以在JDK动态代理和CGLIB动态代理之间转换
CGLIB缺点: 对于final类和final方法,无法进行代理;
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
(利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理>
性能区别1.CGLib 底层采用ASM字节码生成框架 ,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。
唯一需要注意的是,CGLib不能对声明为final类和final方法进行代理,因为CGLIB 原理是动态生成被代理类的子类。
2、在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点
但是到jdk8的时候jdk代理效率高于CGLIB代理。
各自局限1、JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。
2、cglib他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
JDK Proxy 的优势最小化依赖关系,减少依赖意味着简化开发和维护,JDK本身的支持,可能比 cglib 更加可靠。
平滑进行JDK版本升级,而字节码类库通常需要进行更新以保证在新版Java 上能够使用。代码实现简单。
CGLIB的优势∶
从某种角度看,限定调用者实现接口是有些侵入性的实践,类似cglib动态代理就没有这种限制。只操作我们关心的类,而不必为其他相关类增加工作量。另外高性能。
参考博客、参考博客、参考博客、参考博客、视频教程