Spring读源码系列之AOP--05---aop常用工具类学习
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列之AOP--05---aop常用工具类学习相关的知识,希望对你有一定的参考价值。
Spring读源码系列之AOP--05---aop常用工具类学习
- 引言
- 环境搭建
- AopUtils---aop常用方法抽离
- AopConfigUtils---自动代理创建器的管理
- AopNamespaceUtils---xml形式aop处理
- AopProxyUtils---获取代理接口和代理类的相关操作
- AopContext---aop上下文
- AutoProxyUtils---是否应该被代理,获得目标对象类型和是否暴露目标对象
- AspectJAopUtils---前置和后置增强判断
- AspectJProxyUtils----将ExposeInvocationInterceptor放入增强链头部
- ExposeInvocationInterceptor---将当前MethodInvocation放入ThreadLocal中
引言
Spring AOP框架的代码结构组织得不可为不好,良好的面向对象的编程思想,其中很有一部分得益于它对代码的结构的把控。良好的封装、分层、隔离。而在其中起到重要作用的,便是本文要盘点的一些工具类。
Spring框架的工具类,其实它是分为内部工具类和外部工具类的。如果是外部工具类,那是可以给调用者使用的,如果是内部工具类,那它一般都是在Spring的流程内部使用。
环境搭建
public interface HelloService
Object hello();
public class HelloServiceImpl implements HelloService
@Override
public Object hello()
System.out.println("HelloServiceImpl is invoked");
return "hello world";
public class AopUtilMain
public static void main(String[] args)
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new HelloServiceImpl());
proxyFactory.addAdvice((MethodBeforeAdvice)(method, args1, target)->
System.out.println("前置通知~~~");
);
HelloService helloService = (HelloService) proxyFactory.getProxy();
helloService.hello();
System.out.println(helloService.getClass().getName());
测试:
AopUtils—aop常用方法抽离
该工具类是Spring非常重要的一个工具类。显然它是一个外部工具类,我们平时若想要对AOP做一些判断、处理,也是可议使用此工具类的。
public abstract class AopUtils
/**
当前对象是否是代理类,可能被jdk或者cglib动态代理
*/
public static boolean isAopProxy(@Nullable Object object)
return (object instanceof SpringProxy && (Proxy.isProxyClass(object.getClass()) ||
object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)));
/**
是否是jdk动态代理
*/
public static boolean isJdkDynamicProxy(@Nullable Object object)
return (object instanceof SpringProxy && Proxy.isProxyClass(object.getClass()));
/**
是否是cglib动态代理
*/
public static boolean isCglibProxy(@Nullable Object object)
return (object instanceof SpringProxy &&
object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR));
/**
如果传入的对象是代理对象则返回目标对象的类型,否则返回传入对象的class类型
*/
public static Class<?> getTargetClass(Object candidate)
Assert.notNull(candidate, "Candidate object must not be null");
Class<?> result = null;
//TargetClassAware提供了暴露目标对象类型的api
if (candidate instanceof TargetClassAware)
result = ((TargetClassAware) candidate).getTargetClass();
if (result == null)
//是否是被cglib代理的对象,如果是返回代理对象的父类类型即目标对象的class类型
//否在返回当前对象本身的类型
result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
return result;
/**
method在targetType类和其父接口上是否存在,存在就返回
这里targetType通常是代理类
*/
public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType)
if (targetType == null)
return method;
//MethodIntrospector.selectInvocableMethod是去寻找targetType类中是否存在method方法,如果不存在在去targetType
//的父接口中寻找是否存在,存在即返回,否在抛出异常
Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
//当前方法如果是私有的并且是非静态的并且是targetType是代理类
if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&
SpringProxy.class.isAssignableFrom(targetType))
throw new IllegalStateException(String.format(
"Need to invoke method '%s' found on proxy for target class '%s' but cannot " +
"be delegated to target bean. Switch its visibility to package or protected.",
method.getName(), method.getDeclaringClass().getSimpleName()));
//返回找到的这个方法
return methodToUse;
//四个特殊方法的判断
public static boolean isEqualsMethod(@Nullable Method method)
return ReflectionUtils.isEqualsMethod(method);
public static boolean isHashCodeMethod(@Nullable Method method)
return ReflectionUtils.isHashCodeMethod(method);
public static boolean isToStringMethod(@Nullable Method method)
return ReflectionUtils.isToStringMethod(method);
public static boolean isFinalizeMethod(@Nullable Method method)
return (method != null && method.getName().equals("finalize") &&
method.getParameterCount() == 0);
/**
Given a method, which may come from an interface, and a target class used in the current AOP invocation, find the corresponding target method if there is one. E.g. the method may be IFoo.bar() and the target class may be DefaultFoo. In this case, the method may be DefaultFoo.bar(). This enables attributes on that method to be found.
NOTE: In contrast to ClassUtils.getMostSpecificMethod, this method resolves Java 5 bridge methods in order to retrieve attributes from the original method definition.
*/
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass)
Class<?> specificTargetClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, specificTargetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
public static boolean canApply(Pointcut pc, Class<?> targetClass)
return canApply(pc, targetClass, false);
/**
给定的切入点可以完全应用于给定的类吗?
asIntroductions – whether or not the advisor chain for this bean includes any introductions
*/
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)
Assert.notNull(pc, "Pointcut must not be null");
//先从类级别进行过滤
if (!pc.getClassFilter().matches(targetClass))
return false;
//再从方法级别进行过滤
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE)
// No need to iterate the methods if we're matching any method anyway...
return true;
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher)
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
Set<Class<?>> classes = new LinkedHashSet<>();
//目标对象如果不是jdk代理类
if (!Proxy.isProxyClass(targetClass))
//getUserClass会尝试去处理cglib代理的情况,返回代理类的父类类型即目标对象类型---cglib
classes.add(ClassUtils.getUserClass(targetClass));
//加入当前类实现的所有接口---jdk
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//遍历
for (Class<?> clazz : classes)
//拿到当前类型的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
//对每个方法挨个进行匹配
for (Method method : methods)
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass))
return true;
return false;
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions)
//IntroductionAdvisor只需要进行类级别过滤即可
if (advisor instanceof IntroductionAdvisor)
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
else if (advisor instanceof PointcutAdvisor)
PointcutAdvisor pca = (PointcutAdvisor) advisor;
//调用上面分析的重载canApply方法
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
else
// It doesn't have a pointcut so we assume it applies.
//其他类型的advisor没有ponitcut,默认都可以应用
return true;
public static boolean canApply(Pointcut pc, Class<?> targetClass)
return canApply(pc, targetClass, false);
public static boolean canApply(Advisor advisor, Class<?> targetClass)
return canApply(advisor, targetClass, false);
/**
从传入的候选advisors集合中,寻找到能应用到当前calss上的增强器有哪些
*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz)
if (candidateAdvisors.isEmpty())
return candidateAdvisors;
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors)
//如果是IntroductionAdvisor ,那么直接进行类级别过滤级别,调用canApply其中一个重载方法完成类级别的过滤
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz))
//如果发现满足类匹配的条件,加入候选增强器集合
eligibleAdvisors.add(candidate);
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors)
//IntroductionAdvisor上面已经处理过了
if (candidate instanceof IntroductionAdvisor)
// already processed
continue;
//判断ponitcutAdvisor和其他类型的Advisor能否应用
if (canApply(candidate, clazz, hasIntroductions))
eligibleAdvisors.add(candidate);
return eligibleAdvisors;
/**
使用反射调用连接点上的方法
反射调用target上的method方法,传入方法参数args
*/
@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable
// Use reflection to invoke the method.
try
//确保私有方法也可以反射调用
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
catch (InvocationTargetException ex)
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
catch (IllegalArgumentException ex)
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
catch (IllegalAccessException ex)
throw new AopInvocationException("Could not access method [" + method + "]", ex);
AopUtils使用演示
public static void main(String[] args)
HelloService helloService = getProxy(new HelloServiceImpl());
//===============演示AopUtils==================
// AopUtils.isAopProxy:是否是代理对象
System.out.println(AopUtils.isAopProxy(helloService)); // true
System.out.println(AopUtils.isJdkDynamicProxy(helloService)); // false
System.out.println(AopUtils.isCglibProxy(helloService)); // true
// 拿到目标对象
System.out.println(AopUtils.getTargetClass(helloService)); //class com.fsx.service.HelloServiceImpl
// selectInvocableMethod:方法@since 4.3 底层依赖于方法MethodIntrospector.selectInvocableMethod
// 只是在他技术上做了一个判断: 必须是被代理的方法才行(targetType是SpringProxy的子类,且是private这种方法,且不是static的就不行)
// Spring MVC的detectHandlerMethods对此方法有大量调用~~~~~
Method method = ClassUtils.getMethod(HelloServiceImpl.class, "hello");
System.out.println(AopUtils.selectInvocableMethod(method, HelloServiceImpl.class)); //public java.lang.Object com.fsx.service.HelloServiceImpl.hello()
// 是否是equals方法
// isToStringMethod、isHashCodeMethod、isFinalizeMethod 都是类似的
System.out.println(AopUtils.isEqualsMethod(method)); //false
// 它是对ClassUtils.getMostSpecificMethod,增加了对代理对象的特殊处理。。。
System.out.println(AopUtils.getMostSpecificMethod(method,HelloService.class));
}
AopConfigUtils—自动代理创建器的管理
从名字可以看出,这个是关于AOP配置的工具类。因为配置AOP的方式有多种(比如xml、注解等),此工具类就是针对不同配置,提供不同的工具方法的。
它的好处是不管什么配置,最终走底层逻辑都让归一了~~~~
类注释翻译:
该类是来管理自动代理创建器的注册
应该只注册一个自动代理创建者,但可以使用多个具体实现。
此类提供了一个简单的升级协议,允许调用者请求特定的自动代理创建者,并知道该创建者或其更强大的变体将被注册为后处理器。
public abstract class AopConfigUtils
/**
* 这是注册自动代理创建器,默认的BeanName(若想覆盖,需要使用这个BeanName)
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
/**
* 按照升级顺序 存储自动代理创建器(注意这里是升级的顺序 一个比一个强的)
*/
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static
// Set up the escalation list...
//这里每个自动代理创建器都对应一个优先级,优先级就是该自动代理创建器再集合中的下标,下标越大,优先级越高
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.以上是关于Spring读源码系列之AOP--05---aop常用工具类学习的主要内容,如果未能解决你的问题,请参考以下文章
Spring读源码系列之AOP--04---proxyFactory创建代理对象
Spring读源码系列之AOP--02---aop基本概念扫盲---下
Spring读源码系列之AOP--03---aop底层基础类学习
Spring读源码系列之AOP--08--aop执行完整源码流程之自动代理创建器导入的两种方式
Spring读源码系列之AOP--07---aop自动代理创建器(拿下AOP的最后一击)
Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义