Spring AOP的基本实现方式
?Spring AOP,一种模块化机制,可以动态的对切点增加行为,而不破坏原有的代码结构。这是一个很好地动态代理的应用方式,Spring AOP实现依赖于JDK的动态代理库和CGLIB字节码库技术两种来分别实现。
?在Spring AOP中,JdkDynamicAopProxy实现基于JDK动态代理生成代理对象,CglibAopProxy来实现基于CGLIB的动态代理对象生成。并通过DefaultAopProxyFactory进行调用,此处采用策略模式,针对不同场景,调用不同的实现。如下我们对具体实现进行分析,如果对SpringAOP有疑惑的话,可以参考如下文章,一篇是我的博客:http://blog.csdn.net/mergades/article/details/46841079
还有IBM Devloper社区的一篇:http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/
DefaultAopProxyFactory
?Spring AOP内部采用AopProxy对使用不同的代理实现机制进行了适度的抽象,针对不同的代理实现机制提供相应的AopProxy子类实现。DefaultAopProxyFactory实现了AopProxyFactory。其中AopProxyFactory接口定义createAopProxy方法,来决定根据哪种具体的策略来实现代理类。具体实现则由DefaultAopProxyFactory实现,我们查看其对应的createAopProxy方法。
?
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
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()) {//如果是接口,则通过JDK的实现,否则通过CGLIB
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] interfaces = config.getProxiedInterfaces();
return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
}
}
JdkDynamicAopProxy
?基于JDK动态代理的实现,该类实现了InvocationHandler接口,那么我们根据动态代理的知识可以知道,无论调用目标类的什么方法,都会执行该类的Invoke方法,Invoke方法就是Spring AOP加入切面的主要方法。
?我们查看对应的Invoke方法,虽然Invoke方法整体看起来很长很复杂,但是只要我们包握住几个重点即可了解。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
- //1,获取目标对象。
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
- //2,判断对JDK原生方法
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
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;
- //3,设置代理对象
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.
//4,获取目标类
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
//5,获取通知链
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.
//6,判断是否存在通知链,并执行对应方法,获取返回值
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.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
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.
//7,对返回值进行处理
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && 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);
}
}
}
以上是invoke方法的实现,这个方法是动态代理机制较为核心的方法。
下面我们查看在该类中的getProxy方法,查看SpringAOP是如何获取一个代理对象的。
@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);
//获取是否定义equals和hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//调用JDK Proxy生成代理
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
以上两个方法,我们抛开Spring具体各种细节的实现,完全可以看做是一个简单的动态代理模式的应用。
ObjenesisCglibAopProxy
?ObjenesisCglibAopProxy基于CGLIb的AOP代理对象的生成,在DefaultAopProxyFactory类中,通过调用此方法来实现CGLIB生成代理对象。
@Override
@SuppressWarnings("unchecked")
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
try {
//具体生成代理,具体实现源码没有公开
Factory factory = (Factory) this.objenesis.newInstance(enhancer.createClass());
factory.setCallbacks(callbacks);
return factory;
}
catch (ObjenesisException ex) {
// Fallback to regular proxy construction on unsupported JVMs
if (logger.isDebugEnabled()) {
logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex);
}
return super.createProxyClassAndInstance(enhancer, callbacks);
}
}
总结
?如上的各种实现即为Spring AOP对动态代理的应用,我们通过查看以上代码可以看到动态代理的作用,可以不改变原有代码而动态的加入我们自己的操作,这种方式可以实现对我们代码完全的解耦。
?
版权声明:本文为博主原创文章,未经博主允许不得转载。