一、JDK动态代理和CGLIB代理方式:
1、如果目标对象实现了接口,默认会采用JDK代理实现AOP,也可以通过配置强制使用CGLIB实现
2、如果目标对象没有实现接口,必须采用CGLIB库,Spring会自动在JDK方式和CGLIB方式之前转换。
强制使用CGLIB实现:
1.添加CGLIB库,home目录下/cglib/*.jar
2.在spring applicationContext.xml 配置文件中添加<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK动态代理和CGLIB字节码生成的区别:
jdk方式只能针对实现了接口的类,而不能针对类
cglib方式是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为会用到继承,所有目标类和方法不要声明为final
CGLIB包底层通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类,如Groovy和BeanShell,都是使用ASM来生成字节码的。
接着上一节的 spring aop
ProxyFactory类
/** * Create a new proxy according to the settings in this factory. * <p>Can be called repeatedly. Effect will vary if we've added * or removed interfaces. Can add and remove interceptors. * <p>Uses a default class loader: Usually, the thread context class loader * (if necessary for proxy creation). * @return the proxy object */ public Object getProxy() { return createAopProxy().getProxy(); }
JdkDynamicAopProxy类
JdkDynamicAopProxy 类getProxy 追溯到在父类AbstractAutoProxyCreator的postProcessAfterInitialization方法
然后追溯 到refresh方法的doCreate方法 然后再到getBean()方法,也就是BeanFactory接口获取bean的时候就会先查找这个bean里面的所有增强advice,并创建好aop代理Proxy,然后调用的时候就可以调用invoke方法。
@Override public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } @Override public Object getProxy(@Nullable 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); }
/** * Implementation of {@code InvocationHandler.invoke}. * <p>Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; 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; } // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 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. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { //ReflectiveMethodInvocation把拦截器链chain传给了interceptorsAndDynamicMethodMatchers // We need to create a method invocation... 将拦截器封装到ReflectiveMethodInvocation类 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 != Object.class && 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); } } }isAssignableFrom:
class1.isAssignableFrom(class2) 判定此 Class
对象所表示的类或接口与指定的 Class
参数所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true
;否则返回 false
JDK动态代理的关键是创建InvocationHandler,
主要是 构造函数,invoke方法,getProxy方法
例子:
public class Tests { public interface AService{ void test(); } public class AServiceImpl implements AService{ public void test(){ System.out.println("---test---"); } } public class MyInvocationHandler implements InvocationHandler{ private Object target;//目标对象 public MyInvocationHandler(Object target) { super(); this.target = target; } @Override //执行目标对象的方法 public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable { Object result = method.invoke(target, arg2); return result; } public Object getProxy(){ //获取目标对象的代理对象 classLoader指定一个类加载器来加载所生成的代理类的字节码 ClassLoader classLoader = target.getClass().getClassLoader(); //用这个classLoader和Thread.currentThread().getContextClassLoader()的classLoader都能正确代理 //return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this); } } @Test public void testProxy(){ AService a = new AServiceImpl(); MyInvocationHandler in = new MyInvocationHandler(a); AService proxy = (AService)in.getProxy(); proxy.test(); } }
输出:---test---;
ReflectiveMethodInvocation类
@Override @Nullable 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 { // 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); } }
二、拦截器
@FunctionalInterface public interface MethodInterceptor extends Interceptor { /** * Implement this method to perform extra treatments before and * after the invocation. Polite implementations would certainly * like to invoke {@link Joinpoint#proceed()}. * @param invocation the method invocation joinpoint * @return the result of the call to {@link Joinpoint#proceed()}; * might be intercepted by the interceptor * @throws Throwable if the interceptors or the target object * throws an exception */ Object invoke(MethodInvocation invocation) throws Throwable; }
1、MethodBeforeAdviceInterceptor
/** * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}. * Used internally by the AOP framework; application developers should not need * to use this class directly. * * @author Rod Johnson */ @SuppressWarnings("serial") public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; //代表了前置增强AspectMethodBeforeAdvice /** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */ public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); } }
@SuppressWarnings("serial") public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable { public AspectJMethodBeforeAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public void before(Method method, Object[] args, @Nullable Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); } @Override public boolean isBeforeAdvice() { return true; } @Override public boolean isAfterAdvice() { return false; } }AbstractAspectJAdvice类实现了 invokeAdviceMethod方法
/** * Invoke the advice method. * @param jpMatch the JoinPointMatch that matched this execution join point * @param returnValue the return value from the method execution (may be null) * @param ex the exception thrown by the method execution (may be null) * @return the invocation result * @throws Throwable in case of invocation failure */ protected Object invokeAdviceMethod( @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex)); } // As above, but in this case we are given the join point. protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable t) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t)); } protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { Object[] actualArgs = args; if (this.aspectJAdviceMethod.getParameterCount() == 0) { actualArgs = null; } try { ReflectionUtils.makeAccessible(this.aspectJAdviceMethod); // TODO AopUtils.invokeJoinpointUsingReflection return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); } catch (IllegalArgumentException ex) { throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } }invokeAdviceMethodWithGivenArgs方法里面 对apectJAdviceMethod
this.aspectJAdviceMethod.invoke方法 对上面的前置方法进行了调用2、AspectJAfterAdvice 后置增强
前置增强大致结构是 在拦截器链中防止 MethodBeforeAdviceInterceptor,而在MethodBeforeAdviceInterceptor中又防止了AspectJMethodBeforeAdvice,然后调用invoke(相当于用了中间的MethodBeforeAdviceInterceptor 适配器)
而后置增强 没有提供中间的类,直接在拦截器链中使用中间的AspectJAfterAdvice类
/** * Spring AOP advice wrapping an AspectJ after advice method. * * @author Rod Johnson * @since 2.0 */ @SuppressWarnings("serial") public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return true; } }
项目中 调用目标方法时
大致流程是:
1、 调用 JdkDynamicAopProxy类的invoke方法
2、获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
3、执行ReflectiveMethodInvocation中的proceed()方法
4、执行拦截器里面的invoke()方法 如:AspectJAfterAdvice 后置通知里面的invoke 方法
那什么时候调用JdkDynamicAopProxy类的invoke方法呢?
class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable{}
InvocationHandler是JDK定义的反射类的一个接口,这个接口定义了invoke方法,而这个invoke方法是作为JDKProxy代理对象进行拦截的回调入口出现的,JdkDynamicAopProxy实现了InvocationHandler接口,也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数而被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截或者说功能增强的工作
invoke方法是怎么调用的?
动态代理源码分析Proxy类
public class Proxy implements java.io.Serializable 类 实现
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager();////获取安全管理器,安全管理器用于对外部资源的访问控制 //获取安全管理器以及检查是否具有访问权限的过程。安全管理器可能在实际中不太常用,它是为了程序在某些敏感资源的访问上做的权限控制,也就是起到保护程序的作用 if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
//1.2检查是否有访问权限//例如:有的程序不允许你对类进行代理,此时加入安全管理器即可防止你对该类的代理。 } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl);//
//检查的是生成的代理类型做权限检查
} final Constructor<?> cons = cl.getConstructor(constructorParams);//
//cl是代理类型其构造器的参数类型为InvocationHandler,所以参数传入InvocationHandler
/
/因为proxy类构造函数是protected Proxy(InvocationHandler h) {}
所以类型是
InvocationHandler
final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); }//这里是数组 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); //从缓存中获取,如果缓存中没有就通过ProxyClassFactory创建 }
/**
* Look-up the value through the cache. This always evaluates the
* {@code subKeyFactory} function and optionally evaluates
* {@code valueFactory} function if there is no entry in the cache for given
* pair of (key, subKey) or the entry has already been cleared.
*
* @param key possibly null key
* @param parameter parameter used together with key to create sub-key and
* value (should not be null)
* @return the cached value (never null)
* @throws NullPointerException if {@code parameter} passed in or
* {@code sub-key} calculated by
* {@code subKeyFactory} or {@code value}
* calculated by {@code valueFactory} is null.
*/
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
在WeakCache的内部类Factory中 完成了supplier.get()的实现
private final class Factory implements Supplier<V> {
private final K key;
private final P parameter;
private final Object subKey;
private final ConcurrentMap<Object, Supplier<V>> valuesMap;
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
@Override
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);
// try replacing us with CacheValue (this should always succeed)
if (valuesMap.replace(subKey, this, cacheValue)) {
// put also in reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
}
然后在实现里面有一个valueFactory.apply(key, parameter)方法,该方法的实现在Proxy的内部类ProxyClassFactory中
然后再到ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags)
然后里面有一个 final byte[] classFile = gen.generateClassFile();方法用来生成字节码
最后在生成的字节码文件$Proxy0 里面就可以看到
Method m3;
public final int test(Object paramObject) throws { try { return ((Integer)this.h.invoke(this, m3, new Object[] { paramObject })).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
我们在接口中定义的方法test通过反射得到的名字是m3,这里调用代理对象的test方法,
直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
this.h.invoke(this, m3, null);
这invoke方法是怎么调用的部分参考了https://www.jianshu.com/p/9d5ef621f2d1
版权声明:原创文章,转载请注明出处