前言
Spring AOP框架的代码结构组织得不可为不好,良好的面向对象的编程思想,其中很有一部分得益于它对代码的结构的把控。良好的封装、分层、隔离。而在其中起到重要作用的,便是本文要盘点的一些工具类。
Spring框架的工具类,其实它是分为内部工具类和外部工具类的。如果是外部工具类,那是可以给调用者使用的,如果是内部工具类,那它一般都是在Spring的流程内部使用。
Spring AOP工具类盘点
对此我们先构造这么一个环境:
public interface HelloService { Object hello(); } public class HelloServiceImpl implements HelloService { @Override public Object hello() { System.out.println("this is my method~~"); return "service hello"; } // 准备一个私有方法,测试用 private void privateMethod() { System.out.println("privateMethod"); } }
private static HelloService getProxy(Object targetObj){ ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(targetObj); proxyFactory.addAdvice((MethodBeforeAdvice) (method, args1, target) -> { System.out.println("方法之前执行了~~~"); }); HelloService helloService = (HelloService) proxyFactory.getProxy(); helloService.hello(); System.out.println(helloService.getClass().getName()); //com.fsx.service.HelloServiceImpl$$EnhancerBySpringCGLIB$$9b28670f return helloService; }
AopUtils
该工具类是Spring非常重要的一个工具类。显然它是一个外部工具类,我们平时若想要对AOP做一些判断、处理,也是可议使用此工具类的。
下面我们参照一些Demo,来做演示:
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)); }
接下来的几个方法都是关于Pointcut、Advisor的,看源码分析会更好:
public abstract class AopUtils { ... // 判断一个切入点能否匹配一个指定的类型 显然默认是不支持引介匹配 public static boolean canApply(Pointcut pc, Class<?> targetClass) { return canApply(pc, targetClass, false); } //判断一个切入点能否匹配一个指定的类型,是否支持引介匹配; 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(); // 如果是恒等式true,那就毫无疑问全匹配楼 if (methodMatcher == MethodMatcher.TRUE) { return true; } //IntroductionAwareMethodMatcher 是MethodMatcher的子类 增加了匹配方法: // boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<?>> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } 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; } //判断一个建议(advisor)能否匹配一个指定的类型 public static boolean canApply(Advisor advisor, Class<?> targetClass) { return canApply(advisor, targetClass, false); } // 同上,是否包含引介匹配 // 这个原理很简单,判断是否是IntroductionAdvisor还是PointcutAdvisor,然后做对应判断即可 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. // 默认情况都是匹配的 return true; } } //在给定的一组建议(advisor)中,返回能够匹配指定类型的建议者列表 // 这个方法很总要:在自动代理创建器AbstractAdvisorAutoProxyCreator中,都是这样筛选的能够匹配上此类型的Advisor们~~~ public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new LinkedList<>(); // 这里遍历了candidateAdvisors两次 注意这个技巧 // 第一次遍历:找出所有的IntroductionAdvisor 类型的,并且canApply的Advisor们 for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } // hasIntroductions:如果上面不为空,这里就是true 然后继续便利 吧canApply的找出来 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } //通过反射,执行一个目标方法;这个方法其实就是method.invoke方法的更完善的方法,指在target对象上,使用args参数列表执行method @Nullable public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) throws Throwable { try { ReflectionUtils.makeAccessible(method); return method.invoke(target, args); } catch (InvocationTargetException ex) { 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); } } }
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<>(); static { APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); } // 这两个:注册的是`InfrastructureAdvisorAutoProxyCreator` // 调用处为:AutoProxyRegistrar#registerBeanDefinitions(它是一个ImportBeanDefinitionRegistrar实现类) // 而AutoProxyRegistrar使用处为CachingConfigurationSelector,和`@EnableCaching`注解有关 // 其次就是AopNamespaceUtils有点用,这个下面再分析 @Nullable public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); } @Nullable public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAspectJAutoProxyCreatorIfNecessary(registry, null); } // 下面这两个是注入:AspectJAwareAdvisorAutoProxyCreator // 目前没有地方默认调用~~~~和Aop的xml配置方案有关的 @Nullable public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAspectJAutoProxyCreatorIfNecessary(registry, null); } @Nullable public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source); } // 这个就是最常用的,注入的是:AnnotationAwareAspectJAutoProxyCreator 注解驱动的自动代理创建器 // `@EnableAspectJAutoProxy`注入进来的就是它了 @Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null); } @Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } // 这两个方法,很显然,就是处理注解的两个属性值 // proxyTargetClass:true表示强制使用CGLIB的动态代理 // exposeProxy:true暴露当前代理对象到线程上绑定 // 最终都会放到自动代理创建器得BeanDefinition 里面去~~~创建代理的时候会用到此属性值 public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } } public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("exposeProxy", Boolean.TRUE); } } //========上面的注册自动代理创建器IfNecessary之类的方法,最终都是调用了这里======== @Nullable private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { // 这里相当于,如果你自己定义了一个名称为这个的自动代理创建器,那也是ok的(需要注意的是使用工厂方法@Bean的方式定义,这里是会报错的) if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 若使用@Bean的方法定义,这里apcDefinition.getBeanClassName()就是null,导致后面的findPriorityForClass(apcDefinition.getBeanClassName())就会报错~~~~~~~ 需要特别的注意哦~~~~~ if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 绝大部分情况下都会走这里,new一个Bean定义信息出来,然后order属性值为HIGHEST_PRECEDENCE // role是:ROLE_INFRASTRUCTURE属于Spring框架自己使用的Bean // BeanName为:AUTO_PROXY_CREATOR_BEAN_NAME RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } ...findPriorityForClass的逻辑省略 }
备注:请尽量不要自定义自动代理创建器
,也不要轻易使用低级别的创建器,若你对原理不是非常懂的话,慎重
AopNamespaceUtils
这个从名字可以看出,是处理Spring AOP命名空间的工具类。比如
xmlns:aop="http://www.springframework.org/schema/aop
处理这种xml里面的‘
<aop:config /> <aop:advice />
等这种。当然还有对proxy-target-class和expose-proxy的处理。因为接下来的重点都不在xml里,因此此处略过(最终它调用都是AopConfigUtils#XXXIfNecessary的方法,去注册不同的自动代理创建器的)