得到 AopProxy 实例化对象(CglibAopProxy 或 JdkDynamicAopProxy)后,开始创建目标对象的代理对象。
使用JDK动态代理还是CGLIB?
到这里对于到底使用哪种方式的代理可以做一个小总结:
- 如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP。
- 如果目标对象实现了接口,可以强制使用 CGLIB 实现 AOP。
- 如果目标对象没有实现接口,必须采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 之间转换。
强制使用CGLIB代理的方式 <aop:aspectj-autoproxy proxy-target-class="true"/>
JDK 动态代理和 CGLIB 字节码生成的区别?
- JDK 动态代理只能对实现了接口的类生成代理,而不能针对类;
CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成 final。
CglibAopProxy
获🉐代理对象从 getProxy 方法开始 (接口 AopProxy 定义)
首先做的事情就是配置 Enhancer 对象,如下所示:@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
// log
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
// 配置 Enhancer 对象
try {
// 获取需要代理的对象的Class对象
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
// 判断Class是否为cglib生成的Class(会有$$前缀)
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
// 如果是的话,获取其代理的对象的接口们
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
// 验证类的方法是否能代理,不能的话打印下日志
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB 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 ClassLoaderAwareGeneratorStrategy(classLoader));
// 一些回调方法,其中包括我们自定义的增强方法
Callback[] callbacks = getCallbacks(rootClass);
// 回调接口的Class对象
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);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
} catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class", ex);
} catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
然后进入方法 createProxyClassAndInstance 创建代理对象。该方法由子类重写完成。
org.springframework.aop.framework.ObjenesisCglibAopProxy#createProxyClassAndInstance
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
// 代理对象的Class对象
Class<?> proxyClass = enhancer.createClass();
// 代理对象实例
Object proxyInstance = null;
// 尝试使用SpringObjenesis创建对象,不行的话再使用构造方法创建对象
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
} catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
proxyInstance = (this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance());
} catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
JdkDynamicAopProxy
也是从 getProxy 方法开始。
org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
// log
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获得代理对象所有的接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判断接口是否定义了equals和hashcode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// jdk动态代理创建代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy 本身就实现了 InvocationHandler 方法,其invoke方法如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
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;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor 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);
}
}
}