前面我们解读了jkd动态代理方式实现aop的源码,今天我们重点来看下cglib方式实现aop的原理。与JdkDynamicAopProxy一样,CglibAopProxy实现了AopProxy接口,主要是需要用到其getProxy方法来生成代理对象。
1.生成代理对象
getProxy()方法核心逻辑如下:
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;
// 这里判断rootClass是否是Cglib代理所产生的类(内部判断rootClass的className是否包含$$)
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 方法校验,final方法不能被代理,记录日志
validateClassIfNecessary(proxySuperClass, classLoader);
// 配置Enhancer属性,这里ClassLoader需要再看下
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 UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
// 通过callbacks设置拦截器链
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// 设置回调过滤器,修正后的拦截器map和偏移量在这里传进去
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 生成代理类实例
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Exception ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
在创建代理对象的过程中需要对方法的修饰符进行校验,对不能进行代理的方法,也只是打印了日志,并无特殊处理。Modifier类值得一看,方法的各种修饰符是通过一个16进制常量表示的,判断某个方法的修饰符属性时可以通过位运算来得到。
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
if (Object.class != proxySuperClass) {
Method[] methods = proxySuperClass.getDeclaredMethods();
for (Method method : methods) {
int mod = method.getModifiers();
// 静态方法直接跳过
if (!Modifier.isStatic(mod)) {
// final方法不能被代理
if (Modifier.isFinal(mod)) {
logger.info("Unable to proxy method [" + method + "] because it is final: " +
"All calls to this method via a proxy will NOT be routed to the target instance.");
}
// 目标方法方位修饰符为default(意味着该方法仅包内可见),且目标类的类加载器与默认类加载器不相等
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
logger.info("Unable to proxy method [" + method + "] because it is package-visible " +
"across different ClassLoaders: All calls to this method via a proxy will " +
"NOT be routed to the target instance.");
}
}
}
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
}
}
默认类加载器通过ClassUtils.getDefaultClassLoader()获得:
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
// 优先获取线程上下文类加载器
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// 线程上下文类加载器为空,则获取加载ClassUtils的类加载器
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() 为空则意味着是启动类加载器
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
生成代理对象过程中,最重要的一步就是如何产生回调数组callbacks了,spring在这里考虑了很多种情况,将所有callback放到一个数组中。而在某些特定场景下,spring还对回调进行了优化,生成新的回调函数,追加到callbacks数组中。
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimisation choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 我们最常用的就是这个拦截器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();
// 原始的7种callback
Callback[] mainCallbacks = new 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;
// 如果目标类是不可变的(getTarget()方法返回的对象是否一直是同一个,也就是说对单例对象而言,isStatic都返回true),
// 且代理对象被冻结(isFrozen属性设置为true),那么spring将会采取优化,在callbacks数组中增加了新的回调,
// 使用修正后的增强链把aop调用直接转发到目标方法来进行一些优化,也就是说此时代理将不生效
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
// TODO: small memory optimisation 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);
}
// 把默认的7种callback和修正后的callback合并到一个数组中返回
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;
}
2.拦截器
我们主要来看看DynamicAdvisedInterceptor,这种callback与jdk动态代理的实现方式很类似。其intercept()方法如下:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
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 = getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 这里获取拦截器链的方式与jdk动态代理方式调用了同一个方法
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 拦截器链为空,这里为啥还要求必须是公有方法???
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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.
retVal = methodProxy.invoke(target, args);
}
else {
// CglibMethodInvocation继承自ReflectiveMethodInvocation,没有重写proceed()方法,因此获取代理对象后的执行逻辑与jdk动态代理方式完全一样
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
3.Enhancer
接下来具体了解一下Enhancer, 它有两个重要属性:
private CallbackFilter filter;
private Callback[] callbacks;
callback是一个空接口,只是作为回调入口,有了它,我们可以对被代理类的不同方法采用不同的回调,这是jdk动态代理方式所不具备的,它有7个子接口:
/**
* All callback interfaces used by {@link Enhancer} extend this interface.
* @see MethodInterceptor 满足了所有的代理需求,但对于某些特定场景它可能使用起来不太方便。
* @see NoOp 什么操作也不做,代理类直接调用被代理的方法不进行拦截
* @see LazyLoader 适用于被代理对象需要懒加载的场景
* @see Dispatcher 每次调用都会重新加载被代理的对象
* @see ProxyRefDispathcher 与Dispatcher类似,但是它支持传入代理对象
* @see InvocationHandler
* @see FixedValue 锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值
*/
public interface Callback {
}
image.png
而CallbackFilter作为回调过滤器,其核心方法为accept(),返回值为int类型,代表了回调入口在callbacks数组中的位置。假设目标类只有一个方法,如下图所示:
public class Target {
public void exeTarget() {
System.out.println("execute target.");
}
}
此时我们得到的callbacks数组如下:
回调数组.png
Enhancer对象中对应的对调类型如下:
enhancer部分属性.png
可以看到,由于不满足优化条件,回调过滤器中的拦截器map为空,对应的偏移量也为0.
accept()方法核心逻辑如下:
// Constants for CGLIB callback array indices
private static final int AOP_PROXY = 0;
private static final int INVOKE_TARGET = 1;
private static final int NO_OVERRIDE = 2;
private static final int DISPATCH_TARGET = 3;
private static final int DISPATCH_ADVISED = 4;
private static final int INVOKE_EQUALS = 5;
private static final int INVOKE_HASHCODE = 6;
@Override
public int accept(Method method) {
// finalize()方法,直接调用目标类方法,不对其进行增强
if (AopUtils.isFinalizeMethod(method)) {
logger.debug("Found finalize() method - using NO_OVERRIDE");
return NO_OVERRIDE;
}
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Method is declared on Advised interface: " + method);
}
return DISPATCH_ADVISED;
}
// We must always proxy equals, to direct calls to this.
if (AopUtils.isEqualsMethod(method)) {
logger.debug("Found 'equals' method: " + method);
return INVOKE_EQUALS;
}
// We must always calculate hashCode based on the proxy.
if (AopUtils.isHashCodeMethod(method)) {
logger.debug("Found 'hashCode' method: " + method);
return INVOKE_HASHCODE;
}
Class<?> targetClass = this.advised.getTargetClass();
// Proxy is not yet available, but that shouldn't matter.
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
if (haveAdvice || !isFrozen) {
// If exposing the proxy, then AOP_PROXY must be used.
if (exposeProxy) {
if (logger.isDebugEnabled()) {
logger.debug("Must expose proxy on advised method: " + method);
}
return AOP_PROXY;
}
String key = method.toString();
// 如果我们对这个方法的拦截器进行了优化,那么需要使用修正后的拦截器
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
if (logger.isDebugEnabled()) {
logger.debug("Method has advice and optimisations are enabled: " + method);
}
// 返回修正后的回调函数在callbacks数组中的位置,需要加上偏移量
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Unable to apply any optimisations to advised method: " + method);
}
// 如果没有进行优化,直接使用原始的回调函数,我们最常用的就是这个DynamicAdvisedInterceptor,在上面那个例子中,返回的也是这个
return AOP_PROXY;
}
}
else {
// See if the return type of the method is outside the class hierarchy
// of the target type. If so we know it never needs to have return type
// massage and can use a dispatcher.
// If the proxy is being exposed, then must use the interceptor the
// correct one is already configured. If the target is not static, then
// cannot use a dispatcher because the target cannot be released.
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
if (targetClass == returnType) {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type same as target type (may return this) - using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
}
return DISPATCH_TARGET;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type that is assignable from the target type (may return this) - " +
"using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
}
}
到此我们已经大概讲明白了在cglib方式实现aop过程中,代理对象是如何产生的,拦截器是如何工作的以及spring是如何定位到具体的回调函数的,至于代理对象产生的具体细节,且听下回Enhancer源码解析。