看一个最简单的CGLIB的例子,感受一下AOP是如何做到的?
/** * Created with vernon-test * Description: * User: chenyuan * Date: 16/4/25 * Time: 上午9:25 */ public class Target { public String execute() { String message = "----------test()----------"; System.out.println(message); return message; } } /** * Created with vernon-test * Description: * User: chenyuan * Date: 16/4/25 * Time: 上午9:25 */ public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println(">>>MethodInterceptor start..."); Object result = proxy.invokeSuper(obj, args); System.out.println(">>>MethodInterceptor ending..."); return "haha"; } } /** * Created with vernon-test * Description: * User: chenyuan * Date: 16/4/25 * Time: 上午9:28 */ public class CglibProxyTest { public Object createProxy(Class targetClass) { // 第一步 Enhancer enhancer = new Enhancer(); // 第二步 enhancer.setSuperclass(targetClass); // 第三步 enhancer.setCallback(new MyMethodInterceptor()); // 第四步 return enhancer.create(); } public static void main(String rags[]) { CglibProxyTest cglibProxyTest = new CglibProxyTest(); Target proxyTarget = (Target) cglibProxyTest.createProxy(Target.class); String res = proxyTarget.execute(); System.out.println(res); } }
执行后的结果显示
Connected to the target VM, address: '127.0.0.1:55868', transport: 'socket' >>>MethodInterceptor start... ----------test()---------- >>>MethodInterceptor ending... haha Disconnected from the target VM, address: '127.0.0.1:55868', transport: 'socket'
实际上在执行execute()的前后就各自做了自己想要的操作。其实这个就是Spring AOP对简单的一个原型。
在Spring中 TransactionInterceptor
和 PlatformTransactionManager
这两个类是整个事务模块的核心, TransactionInterceptor
负责拦截方法执行,进行判断是否需要提交或者回滚事务。 PlatformTransactionManager
是Spring 中的事务管理接口,真正定义了事务如何回滚和提交。我们重点研究下这两个类的源码。
TransactionInterceptor
类中的代码有很多,我简化一下逻辑,方便说明:
//以下代码省略部分内容 public Object invoke(MethodInvocation invocation) throws Throwable { //获取事务调用的目标方法 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); //执行带事务调用 return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }
其实,这里也就是因为用到了动态代理。在事务回滚这个动作的前前后后可以做自己想要的东西。这是一个非常重要的设计思想。如果我们自己要写框架,这个模式可以作为你的第一参考。
我们看了解一下它是如何仿照最上面的code来写的?
仿照上面Demo的第一步:
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + 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); } } // 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); } } // 第二点:setSuperclass enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); // 第三点:获取Callback 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); // 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); } }
仿照上面Demo的第三步:
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). 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[] { 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<>(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; }
仿照上面Demo的第四步:
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); return (this.constructorArgs != null && this.constructorArgTypes != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create()); }
上面的几步就完成了一个动态代理的流程,就只需要真的发生调用的时候去执行动态代理类了。
这里说下在同一个类中,一个非@Transaction的方法调用有@Transaction的方法不会生效。如果是在同一个类中的方法调用,则不会被方法拦截器拦截到,因此事务不会起作用,必须将方法放入另外一个类中,并且该类通过Spring注入。
Spring 采用动态代理(AOP)实现对Bean的管理和切片,它为我们的每个class生成一个代理对象,只有在代理对象之间进行调用时,可以触发切面逻辑。
而在同一个类中,方法B调用A,调用的事元对象的方法,而不是通过代理对象,所以spring无法切到这次调用,也就是无法通过注解保证事务性。
如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员简栈文化-小助手(lastpass4u),他会拉你们进群。