您的位置:首页 > 编程语言 > Java开发

spring aop 创建代理

2016-12-18 00:00 357 查看

spring aop 创建代理

我们知道spring org\springframework\aop\framework\DefaultAopProxyFactory.java#createAopProxy的方法返回的JdkDynamicAopProxy 或 CglibProxyFactory 实现了创建代理类的逻辑,分别支持jdk和cglib两种代理方式。

jdk 代理方式仅支持对一个接口创建代理对象,也就是被代理的对象必须实现某个接口。

cglib 代理主要是针对类实现代理,基本实现思路是动态生成被代理类的子类,从而可以代理父类的所有方法。

在了解spring aop实现逻辑之前我们先回顾一下这两种代理方式。

jdk 代理

回顾

package framework.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 这是 spring  JdkDynamicAopProxy 的精简版实现,
* 其实原理很简单,spring也是用Proxy和 InvocationHandler 这两个类创建代理对象。
*
* 在整个过程中,InvocationHandler 的 invoke 方法最重要,所有的代理逻辑全部在这里实现。
*/
public class JdkProxyDemo {
public static void main(String[] args) {
FooInterface foo = new FooImpl();
FooHandler fooHandler = new FooHandler(foo);
foo = (FooInterface)fooHandler.getProxy();
foo.hello();
}
}

interface FooInterface{
void hello();
}

class FooImpl implements  FooInterface{

@Override
public void hello() {
System.out.println("hello.");
}
}

class FooHandler implements InvocationHandler{

Object target;
public FooHandler(Object obj){
this.target = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
Object result = method.invoke(target,args);
System.out.println("after...");
return result;
}

public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(),this);
}
}

运行结果如下:

before...
hello.
after...

spring 实现

JdkDynamicAopProxy的getProxy方法返回代理方法

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);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

我们知道 jdk 代理的关键逻辑是在invoke中,下面是sping 的实现

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 {
// equals 方法的处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hascode 方法的处理
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}

/*
class 类的isAssignableFrom(Class cls)方法:
如果调用这个方法的是class或接口与参数cls表示的类或接口相同,
或者是参数cls表示的类或接口的弗雷,则返回true.
形象地:自身类.class.isAssignableFrom(自身类或四类.class) 返回true
eg.
System.out.println(ArrayList.class.isAssignableFrom(Object.class) == false);
System.out
7fe8
.println(Object.class.isAssignableFrom(ArrayList.class) == true);

*/
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<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.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// importance 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.
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);
}
}
}

上面最重主要的工作就是创建一个 ReflectiveMethodInvocation 封装了连接器链。

ReflectiveMethodInvocation#proceed

public Object proceed() throws Throwable {
//	We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}

//		获取下一个要执行的拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
//			普通拦截器,直接调用拦截器,如:
//			ExposeInvocationInterceptor
//			DelegatePertargetObjectInteroductionInterceptor
//			MethodBeforeAdviceInterceptor
//			AspectJAroundAdvice
//			AspectJAfterAdvice
//			将 this作为参数传递一保证当前实例中调用连的执行
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

这个方法的逻辑并不负责,主要负责责任链的调用,记录当前责任链调用位置,以便有序的进行调用。

cglib代理

回顾

CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实 现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿 (moke)对象。

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。当不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文 件的格式和指令集都很熟悉。

public class CglibEnhancerDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CglibEnhancerDemo.class);
enhancer.setCallback(new MethodInterceptorImpl());

CglibEnhancerDemo demo = (CglibEnhancerDemo)enhancer.create();
demo.test();
System.out.println(demo);
}

public void test() {
System.out.println("test...");
}

private static class MethodInterceptorImpl implements MethodInterceptor{
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before invoke" + method);
Object result = methodProxy.invokeSuper(o,objects);
System.out.println("after invoke"+method);
return result;
}
}
}

cglib 是通过吧MethodInterceptor加到 callBack中,对于方法的链接是通过连接器中的intercept方法来实现的。在吧MethodInterceptor加入到callback中后,在调用代理是会直接调用intercept方法,实现代理逻辑。

运行结果如下

before invoke public void bean.aop.CglibEnhancerDemo.test()
test...
after invoke public void bean.aop.CglibEnhancerDemo.test()
before invoke public java.lang.String java.lang.Object.toString()
before invoke public native int java.lang.Object.hashCode()
after invoke public native int java.lang.Object.hashCode()
after invoke public java.lang.String java.lang.Object.toString()
bean.aop.CglibEnhancerDemo$$EnhancerByCGLIB$$efbf68ac@a8ceb6

我们看到System.out.println(demo)这行代码运行时,会调用对象的toString,hasCode,最后打印的是bean.aop.CglibEnhancerDemo$$EnhancerByCGLIB$$efbf68ac@a8ceb6,是由cglib运行时产生的代理对象。

spring 实现

spring 委托CglibAopProxy创建 cglib 代理,看过了 jdk代理的初始化方式,我们知道 getProxy 方法肯定实现了 Enhancer 的创建和接口的封装。

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;
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.
//			验证class
validateClassIfNecessary(proxySuperClass);

// Configure CGLIB Enhancer...
// 创建和配置 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 MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterceptDuringConstruction(false);

//importance 设置拦截器
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
enhancer.setCallbacks(callbacks);

// Generate the proxy class and create a proxy instance.
//			生成代理类,创建对象
Object proxy;
if (this.constructorArgs != null) {
proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
}
else {
proxy = enhancer.create();
}

return proxy;
}
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);
}
}

这里最重要的而是通过 getCallbacks 方法设置连接器链。

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();

// Choose an "aop" interceptor (used for AOP calls).
//		将拦截器封装在 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();

Callback[] mainCallbacks = new Callback[]{
//				将拦截器加入 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 optimisations 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<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);
}

// 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;
}

spring在这个方法里考虑了很多情况,如exposeProxy暴露代理对象等,我们只解释DynamicAdvisedInterceptor。DynamicAdvisedInterceptor加入callBack实现代理逻辑,核心逻辑一定在intercept方法中。

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

private final AdvisedSupport advised;

public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}

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();
}
//				获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
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 {
// We need to create a method invocation...
//					调用拦截器链
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);
}
}
}

总结

不管是jdk代理还是cglib代理,都是首先构造责任链,然后封装此链记性串联调用,稍微有些区别就是jdk中直接构造ReflectiveMethodInvocation,而cglib中使用CglibMethodInvocation。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring aop