Cglib 与 JDK动态代理
作者:xiaolyuh
时间:2019/09/20 09:58
AOP 代理的两种实现:
- jdk是代理接口,私有方法必然不会存在在接口里,所以就不会被拦截到;
- cglib是子类,private的方法照样不会出现在子类里,也不能被拦截。
JDK 动态代理。
具体有如下四步骤:
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
示例
创建业务接口
public interface UserService {
/**
* 需要增强的方法
*/
void add();
}
创建业务接口 实现类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("-------------业务逻辑方法 add ------------");
}
}
创建自定义的 InvocationHandler,用于对接口提供的方法进行增强
public class MyInvocationHandler implements InvocationHandler {
/**
* 需要增强的对象
*/
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
/**
* 执行目标对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-------------方法执行前的增强逻辑 ------------");
Object result = method.invoke(target, args);
System.out.println("-------------方法执行后的增强逻辑 ------------");
return result;
}
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
}
}
测试类
public class ProxyTest {
@Test
public void contextTest() {
// 实例化目标对象
UserService userService = new UserServiceImpl();
// 实例化 InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
// 生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();
// 输出代理类的class
ProxySourceClassUtil.writeClassToDisk("C:\\Users\\yuhao.wang3\\Desktop\\" + proxy.getClass().getSimpleName() + ".class", proxy.getClass().getSimpleName(), UserService.class);
// 调用代理对象的方法
proxy.add();
}
}
输出结果:
Connected to the target VM, address: '127.0.0.1:60738', transport: 'socket'
-------------方法执行前的增强逻辑 ------------
-------------业务逻辑方法 add ------------
-------------方法执行后的增强逻辑 ------------
Disconnected from the target VM, address: '127.0.0.1:60738', transport: 'socket'
用起来很简单,其实’这基本上就 AOP 的一个简单实现了,在目标对象的方法执行之前和 执行之后进行了增强。 Spring的AOP实现其实也是用了 Proxy 和 InvocationHandler。在整个创建过程中InvocationHandler的创建最为核心,在自定义的InvocationHandler中需要重新3个函数:
- 构造函数,将代理的对象传入。
- invoke方法,此方法中实现了AOP增强的所有逻辑。
- getProxy方法,此方千篇一律,但是必不可少。
反编译代理类结果
package com.xiaolyuh.aop.jdk;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// 代理类会去实现我们的接口
public final class Proxy4 extends Proxy implements UserService {
// 解析所有的方法
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public Proxy4() throws {
super(paramInvocationHandler);
}
public final boolean equals() throws {
try {
return ((Boolean) this.h.invoke(this, m1, new Object[]{paramObject})).booleanValue();
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString() throws {
try {
return ((String) this.h.invoke(this, m2, null));
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void add() throws {
try {
// 通过InvocationHandler的invoke方法去执行增强和原有方法逻辑
this.h.invoke(this, m3, null);
return;
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode() throws {
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
static {
try {
// 解析所有的method出来
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.xiaolyuh.aop.jdk.UserService").getMethod("add", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
从结果我们可以看出,代理类会实现我们的接口,并会实现我们接口中的方法。然后通过InvocationHandler的invoke方法去执行增强逻辑和原有方法逻辑。在invoke中我们可以使用反射去执行原有逻辑,并在方法执行前后加上自己的增强逻辑。
JdkDynamicAopProxy
JdkDynamicAopProxy是Spring中JDK动态代理的实现,它也实现了InvocationHandler接口。核心方法:
- getProxy:获取代理对象,这个和上面的示例几乎是一样的
- invoke:实现了AOP的核心逻辑
源码:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
...
/** Config used to configure this proxy(对增强器的支持) */
private final AdvisedSupport advised;
...
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
// 获取目标类接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 返回代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
...
/**
* Implementation of {@code InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
// equals 方法处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hashCode 方法处理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 有时候目标对象内部的自我调用无法实施切面中的增强则需要通过此属性暴露代理
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取当前方法的拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 如果没有拦截链那么直接调用切点方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 将拦截器封装在ReflectiveMethodInvocation中,以便使用proceed方法执行拦截链
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行拦截链
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
...
}
GCLIB代理
cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
- cglib封装了asm,可以在运行期动态生成新的class(子类)。
- cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。
示例
需要代理的类
public class EnhancerDemo {
public void test() {
System.out.println("-------------业务逻辑方法 test ------------");
}
}
MethodInterceptor的实现类(增强器)
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MethodInterceptorImpl implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("-------------方法执行前的增强逻辑 ------------" + method);
Object result = methodProxy.invokeSuper(object, args);
System.out.println("-------------方法执行后的增强逻辑 ------------" + method);
return result;
}
}
测试类:
public class EnhancerTest {
@Test
public void contextTest() {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(EnhancerDemo.class);
enhancer.setCallback(new MethodInterceptorImpl());
EnhancerDemo proxy = (EnhancerDemo) enhancer.create();
proxy.test();
System.out.println(proxy);
}
}
执行结果
Connected to the target VM, address: '127.0.0.1:61217', transport: 'socket'
-------------方法执行前的增强逻辑 ------------public void com.xiaolyuh.aop.cglib.EnhancerDemo.test()
-------------业务逻辑方法 test ------------
-------------方法执行后的增强逻辑 ------------public void com.xiaolyuh.aop.cglib.EnhancerDemo.test()
-------------方法执行前的增强逻辑 ------------public java.lang.String java.lang.Object.toString()
-------------方法执行前的增强逻辑 ------------public native int java.lang.Object.hashCode()
-------------方法执行后的增强逻辑 ------------public native int java.lang.Object.hashCode()
-------------方法执行后的增强逻辑 ------------public java.lang.String java.lang.Object.toString()
com.xiaolyuh.aop.cglib.EnhancerDemo$$EnhancerByCGLIB$$da6c48f9@7a187f14
Disconnected from the target VM, address: '127.0.0.1:61217', transport: 'socket'
可以看到 System.out.println(porxy); 首先调用了 toString() 方法,然后又调用了 hashCode() ,生成的对象为 EnhancerDemo$$EnhancerByCGLIB$$da6c48f9@7a187f14
的实例,这个类是运行时由 CGLIB 产生。
反编译代理结果
在测试类的第一行加上下面语句,那么在cglib中生成的class文件将会持久化到硬盘。https://www.cnblogs.com/cruze/p/3847968.html
// 该设置用于输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
// 该设置用于输出jdk动态代理产生的类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
反编译结果:
package com.xiaolyuh.aop.cglib;
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 da6c48f9 extends EnhancerDemo
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$test$0$Method;
private static final MethodProxy CGLIB$test$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1()
{
Class localClass2;
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class localClass1 = Class.forName("com.xiaolyuh.aop.cglib.EnhancerDemo$$EnhancerByCGLIB$$da6c48f9");
Method[] tmp83_80 = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = tmp83_80[0];
CGLIB$equals$1$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
Method[] tmp103_83 = tmp83_80;
CGLIB$toString$2$Method = tmp103_83[1];
CGLIB$toString$2$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
Method[] tmp123_103 = tmp103_83;
CGLIB$hashCode$3$Method = tmp123_103[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$3");
Method[] tmp143_123 = tmp123_103;
CGLIB$clone$4$Method = tmp143_123[3];
CGLIB$clone$4$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
tmp143_123;
Method[] tmp191_188 = ReflectUtils.findMethods(new String[] { "test", "()Ljava/lang/String;" }, (localClass2 = Class.forName("com.xiaolyuh.aop.cglib.EnhancerDemo")).getDeclaredMethods());
CGLIB$test$0$Method = tmp191_188[0];
CGLIB$test$0$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "test", "CGLIB$test$0");
tmp191_188;
}
final String CGLIB$test$0()
{
return super.test();
}
public final String test()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
return ((String)tmp17_14.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy));
return super.test();
}
final boolean CGLIB$equals$1()
{
return super.equals(paramObject);
}
public final boolean equals()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 == null)
break label57;
label50: label57: if (tmp17_14.intercept(this, CGLIB$equals$1$Method, new Object[] { paramObject }, CGLIB$equals$1$Proxy) != null)
break label50;
}
final String CGLIB$toString$2()
{
return super.toString();
}
public final String toString()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
return ((String)tmp17_14.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy));
return super.toString();
}
final int CGLIB$hashCode$3()
{
return super.hashCode();
}
public final int hashCode()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 == null)
break label52;
label45: label52: if (tmp17_14.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy) != null)
break label45;
}
final Object CGLIB$clone$4()
throws CloneNotSupportedException
{
return super.clone();
}
protected final Object clone()
throws CloneNotSupportedException
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
return tmp17_14.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
return super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature)
{
String tmp4_1 = paramSignature.toString();
switch (tmp4_1.hashCode())
{
case -508378822:
if (!(tmp4_1.equals("clone()Ljava/lang/Object;")))
break label121;
label121: return CGLIB$clone$4$Proxy;
case 225925469:
case 1826985398:
case 1913648695:
case 1984935277:
}
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
{
CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
{
CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
}
private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
{
da6c48f9 localda6c48f9 = (da6c48f9)paramObject;
if (localda6c48f9.CGLIB$BOUND)
break label52;
localda6c48f9.CGLIB$BOUND = true;
Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
if (tmp23_20 != null)
break label39;
tmp23_20;
Callback[] tmp31_28 = CGLIB$STATIC_CALLBACKS;
if (tmp31_28 != null)
break label39;
tmp31_28;
label39: label52: break label52:
}
public Object newInstance()
{
CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
CGLIB$SET_THREAD_CALLBACKS(null);
return new da6c48f9();
}
public Object newInstance()
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
CGLIB$SET_THREAD_CALLBACKS(null);
return new da6c48f9();
}
public Object newInstance(, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback)
{
CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
Class[] tmp9_8 = paramArrayOfClass;
switch (tmp9_8.length)
{
case 0:
tmp9_8;
break;
default:
new da6c48f9();
throw new IllegalArgumentException("Constructor not found");
}
CGLIB$SET_THREAD_CALLBACKS(null);
}
public Callback getCallback()
{
CGLIB$BIND_CALLBACKS(this);
switch (paramInt)
{
case 0:
}
return null;
}
public void setCallback(, Callback paramCallback)
{
switch (paramInt)
{
case 0:
this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramCallback);
}
}
public Callback[] getCallbacks()
{
CGLIB$BIND_CALLBACKS(this);
return { this.CGLIB$CALLBACK_0 };
}
public void setCallbacks()
{
this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramArrayOfCallback[0]);
}
static
{
CGLIB$STATICHOOK1();
}
}
从结果上我们可以看出Cglib是使用继承的方式实现的动态代理。关键代码:
public final String test()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
return ((String)tmp17_14.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy));
return super.test();
}
从上面的代码我们可以发现方法的执行会委托给MethodInterceptor的intercept方法。从而实现对方法的增强。
由于 Cglib 是使用继承方式,所有final类和方法是不能使用cglib代理的,会直接抛出异常。
CglibAopProxy
CglibAopProxy是Spring中Cglib动态代理的实现,在getProxy方法中完成了对Enhancer的创建和封装。在getProxy方法中getCallbacks(rootClass);
方法会将拦截链封装成DynamicAdvisedInterceptor对象,并放到Cglib的回调函数中。源码如下:
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 验证Class
validateClassIfNecessary(proxySuperClass, classLoader);
// 创建以及配置Enhancer
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 将拦截链放到回调中
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 生成代理类并创建代理实例
return createProxyClassAndInstance(enhancer, callbacks);
}
...
}
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
// 将拦截链封装到DynamicAdvisedInterceptor中
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
}
else {
targetInterceptor = isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}
// Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
Callback[] mainCallbacks = new Callback[] {
// 将拦截链加入到CallBack中
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods[x].toString(), x);
}
// Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
原理区别:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
- 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
- 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
- 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
Cglib 与 JDK动态代理的运行性能比较
结论:从 jdk6 到 jdk7、jdk8 ,动态代理的性能得到了显著的提升,尤其是JDK7和JDK8性能表现都比cglib好,而 cglib 的表现并未跟上,甚至可能会略微下降。所以建议尽量使用 JDK 的动态代理。
https://my.oschina.net/u/3748347/blog/3108376/print
Cglib 与 JDK动态代理的更多相关文章
- 学习CGLIB与JDK动态代理的区别
动态代理 代理模式是Java中常见的一种模式.代理又分为静态代理和动态代理.静态代理就是显式指定的代理,静态代理的优点是由程序员自行指定代理类并进行编译和运行,缺点是一个代理类只能对一个接口的实现类进 ...
- Cglib 与 JDK动态代理的运行性能比较
都说 Cglib 创建的动态代理的运行性能比 JDK 动态代理能高出大概 10 倍,今日抱着怀疑精神验证了一下,发现情况有所不同,遂贴出实验结果,以供参考和讨论. 代码很简单,首先,定义一个 Test ...
- 面试造火箭系列,栽在了cglib和jdk动态代理
"喂,你好,我是XX巴巴公司的技术面试官,请问你是张小帅吗".声音是从电话那头传来的 "是的,你好".小帅暗喜,大厂终于找上我了. "下面我们来进行一 ...
- 输出cglib以及jdk动态代理产生的class文件
--该设置用于输出jdk动态代理产生的类 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles&q ...
- CGlib和JDK动态代理
一.CGlib动态代理 JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了.CGLib采用了非常底层的1:字节码技术,其原理是通过字节 ...
- spring cglib 与 jdk 动态代理
1. 概述 JDK动态代理是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理 Cglib动态代理是 利用asm开源包 把被代理类的clas ...
- 有点深度的聊聊JDK动态代理
在接触SpringAOP的时候,大家一定会被这神奇的功能所折服,想知道其中的奥秘,底层到底是如何实现的.于是,大家会通过搜索引擎,知道了一个陌生的名词:动态代理,慢慢的又知道了动态代理有多种实现方式, ...
- java学习笔记(中级篇)—JDK动态代理
一.什么是代理模式 相信大家都知道代理商这个概念,在商业中,代理商无处不在.假设你要去买东西,你不可能去找真正的厂家去买,也不可能直接跟厂家提出需求,代理商就是这中间的一桥梁,连接买家和厂商.你要买或 ...
- AOP学习心得&jdk动态代理与cglib比较
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
随机推荐
- Docker搭建Nexus(Maven私库)
0.镜像的查找:docker search nexus 1.拉取官方镜像:docker pull sonatype/nexus3 2.创建了自己的目录 (/opt/nexus/nexus-data) ...
- Shiro RememberMe 1.2.4 反序列化漏洞详细复现
0x00 前言 今天上班的时候收到了一个复测的任务,打开一看,shiro反序列化漏洞,What?这是个什么东西,经百度查找后才知道,原来是Java的开发框架,好吧,还是没听说过..由于初测报告上的过程 ...
- UGUI:窗口限制以及窗口缩放
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...
- Python基础A(执行方式---注释)
执行Python程序的两种方式 交互式(jupyter) 优点:运行一句,执行一句 缺点:关闭即消失 命令行式(pycharm) 优点:可以一直保存下去 缺点:全部写完才能调试bug 虽然txt问价可 ...
- USACO Slowing down
洛谷 P2982 [USACO10FEB]慢下来Slowing down 洛谷传送门 JDOJ 2684: USACO 2010 Feb Gold 3.Slowing down JDOJ传送门 Des ...
- matlab-fsolve函数求解多元非线性方程
记录一下代码,方便下次套用模板 options=optimset('MaxFunEvals',1e4,'MaxIter',1e4); [x,fval,exitflag] = fsolve(@(x) m ...
- java的excel表格的导出与下载
今天做一个java对excel表格的导出和下载的时候,从网络上搜寻了下载的模板,代码如下: 控制层: @RequestMapping(value = "excelOut_identifier ...
- js判断客户端是iOS还是Android移动终端
前段时间,小颖公司需要实现:用户在微信中打开一个html5,在该html5中通过点击下载按钮,Android手机会跳到Android的下载地址,IOS会跳转到IOS下载地址,其它则跳转到另一个指定地址 ...
- 【CSP-S膜你考】那23个路口
那23个路口 题面 故事的起源不加赘述,那23个路口. 单刀直入,我直接说题的意思. 蚊子和疯子在做一件事,就是他们要在茫茫的大街上找一个出发点,然后从出发点开始,经过上下左右23次拐弯,到达一个他们 ...
- 【JZOJ100207】【20190705】决心
题目 你需要构造一个排列 初始时\(p_i=i\),一次操作定义为: 选择一些\((x_i,y_i)\),满足每个数字只能出现一次 依次交换\(p_{x_i},p_{y_i}\) 定义一个排列 \(P ...