你知道spring事务是如何嵌套到你的业务代码中的吗?如果你告诉我是通过动态代理实现的,那么我可以告诉你,你的技术水平仅仅停留在初级阶段。下面我通过几篇文章来慢慢分析spring是怎么将事务代码嵌入到你的业务逻辑代码里面。
springAOP简单的demo1
- Waiter 接口
- NaiveWaiter Waiter的实现类
- GreetingBeforeAdvice前置通知(或者叫做前置增强)
- TestBeforeAdvice测试类
代码如下
Waiter接口
package com.spring.start.aop;
/**
* @Author: chao.zhu
* @description:
* @CreateDate: 2018/12/29
* @Version: 1.0
*/
public interface Waiter {
void greetTo(String name);
void serveTo(String name);
}
NaiveWaiter实现类
package com.spring.start.aop;
/**
* @Author: chao.zhu
* @description:
* @CreateDate: 2018/12/29
* @Version: 1.0
*/
public class NaiveWaiter implements Waiter {
@Override
public void greetTo(String name) {
System.out.println("greetTo:"+name);
}
@Override
public void serveTo(String name) {
System.out.println("serveTo:"+name);
}
}
GreetingBeforeAdvice前置通知
package com.spring.start.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* @Author: chao.zhu
* @description:
* @CreateDate: 2018/12/29
* @Version: 1.0
*/
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
String clientName = (String)objects[0];
System.out.println("hhh:"+clientName);
}
}
测试类
下面测试类是通过ProxyFactory创建代理对象Waiter当调用Waiter的方式的时候会进入代理类执行代理类的逻辑。因为设置了代理目标pf.setTarget(tager);
还有设置了增强类型。代理会按照约定执行增强和Waiter的方法
package com.spring.start.aop;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
/**
* @Author: chao.zhu
* @description:
* @CreateDate: 2018/12/29
* @Version: 1.0
*/
public class TestBeforeAdvice {
public static void main(String[] args) {
Waiter tager = new NaiveWaiter();
BeforeAdvice advice = new GreetingBeforeAdvice();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(tager);
pf.addAdvice(advice);
Waiter proxy = (Waiter)pf.getProxy();
proxy.greetTo("aaa");
proxy.serveTo("bbb");
}
}
运行结果
hhh:aaa
greetTo:aaa
hhh:bbb
serveTo:bbb
Process finished with exit code 0
可以看到执行结果会先执行我们的设置的前置通知(前置增强)然后才执行正真的业务代码。只要你对动态代理比较熟悉上面的代码应该可以猜个七七八八。下面我们再来看看spring是如何实现的
源码分析
我们按照测试类的代码顺序来逐一分析spring的源码。准备发车.....
实例化
先来看一下ProxyFactory
的类结构
我们知道实例化的过程是先实例父类,然后实例子类,所以我们要挨个看一下每一个父类,子类的实例调用了那些方法。下面代码从
ProxyConfig到ProxyFactory
的顺序列出构造函数
//org.springframework.aop.framework.ProxyConfig
没有构造函数,使用默认的无参构造函数
//org.springframework.aop.framework.AdvisedSupport#AdvisedSupport()
public AdvisedSupport() {
initMethodCache();
}
private void initMethodCache() {
this.methodCache = new ConcurrentHashMap>(32);
}
//org.springframework.aop.framework.ProxyCreatorSupport#ProxyCreatorSupport()
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
//org.springframework.aop.framework.ProxyFactory#ProxyFactory()
public ProxyFactory() {
}
上面一些列的构造函数都比较简单,实例了一个DefaultAopProxyFactory
实例了一个Map用来做缓存。Waiter proxy = (Waiter)pf.getProxy();
从ProxyFactory里面获取代理类。看一下实现方式
public Object getProxy() {
return createAopProxy().getProxy();
}
创建生成代理类的工厂,然后生成代理类。在spring中一般使用JDK的动态代理或者CGLib的方式生成代理类。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
上面 就是判断是用Jdk的方式还是Cglib的方式。我们之分析一下jdk的方式
@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);
}
我们知道在动态代理中生成的proxy代理类在执行方法的时候都是执行invoke方法。可以在JdkDynamicAopProxy
里面找到invoke方法
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 {
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;
}
// 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();
}
// Get the interception chain for this method.
List
这就是我们使用编码的方式实现AOP的简单例子。源码实现也很简单。就是设置需要代理的目标对象,设置代理对象的增强,通过代理类生工厂生成代理类。这个代理类工厂有两种:JDK的方法,Cglib的方式。生成代理类之后再执行方法的时候都是调用代理类的invoke方法。然后在invoke方法里面执行增强和目标对象的方法。
附上增强结构图