一、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);
}
}
}
//获取拦截器链
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

本文深入解析了面向切面编程(AOP)的实现原理,重点介绍了JDK动态代理和CGLIB代理的方式及其区别,详细解释了如何通过Spring框架实现AOP,包括拦截器的运作机制及如何创建和调用代理对象。
最低0.47元/天 解锁文章
23万+

被折叠的 条评论
为什么被折叠?



