马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
前面的文章介绍了 spring 引入 AspectJ 之后,基于注解实现 AOP 的过程分析,本日我们来看下AspectJ 基于 XML 的 AOP 实现逻辑。
XML 的实现示例可以参考 AspectJ 对于 AOP 的实现。
aop:config 标签解析
先去 spring-aop 模块下,META-INF/spring.handlers 中查看 aop 定名空间对应的处置惩罚器为 AopNamespaceHandler。在 AopNamespaceHandler#init 方法中发现为 config 标签注册的解析器为 org.springframework.aop.config.ConfigBeanDefinitionParser。
- // ConfigBeanDefinitionParser
- @Override
- @Nullable
- public BeanDefinition parse(Element element, ParserContext parserContext) {
- CompositeComponentDefinition compositeDef =
- new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
- parserContext.pushContainingComponent(compositeDef);
- // 配置自动代理生成器
- configureAutoProxyCreator(parserContext, element);
- // 解析 aop:config 子节点
- List<Element> childElts = DomUtils.getChildElements(element);
- for (Element elt: childElts) {
- String localName = parserContext.getDelegate().getLocalName(elt);
- if (POINTCUT.equals(localName)) {
- parsePointcut(elt, parserContext);
- }
- else if (ADVISOR.equals(localName)) {
- parseAdvisor(elt, parserContext);
- }
- else if (ASPECT.equals(localName)) {
- parseAspect(elt, parserContext);
- }
- }
- parserContext.popAndRegisterContainingComponent();
- return null;
- }
复制代码 主要逻辑如下:
- 配置主动署理生成器
- 解析 aop:config 标签子节点
配置主动署理生成器
- private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
- AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
- }
- public static void registerAspectJAutoProxyCreatorIfNecessary(
- ParserContext parserContext, Element sourceElement) {
- // 注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition
- BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
- parserContext.getRegistry(), parserContext.extractSource(sourceElement));
- // 处理 proxy-target-class 和 expose-proxy 两个属性
- useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
- registerComponentIfNecessary(beanDefinition, parserContext);
- }
- @Nullable
- public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
- BeanDefinitionRegistry registry, @Nullable Object source) {
- return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
- }
复制代码 实在就是在 BeanFactory 中注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition,假如 aop:config 设置了 proxy-target-class 和 expose-proxy 两个属性,则为这个注册的 BeanDefinition 也设置这两个属性,添加 proxyTargetClass 和 exposeProxy 到 propertyValues 中,供 bean 对象创建时使用。
解析 config 标签子节点
aop:config 共支持三种类型的子节点。分别如下:
- pointcut 定义切入点,配置切入点表达式
- advisor 自定义 Advisor,需要一个 Advice
- aspect 需对应一个切面类
在 ConfigBeanDefinitionParser#parse 中定义了三个分支分别解析对应的子节点 。
pointcut
- // ConfigBeanDefinitionParser
- private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
- // 获取 pointcut 标签 id 和 expression 两个属性
- String id = pointcutElement.getAttribute(ID);
- String expression = pointcutElement.getAttribute(EXPRESSION);
- AbstractBeanDefinition pointcutDefinition = null;
- try {
- this.parseState.push(new PointcutEntry(id));
- // 一个 pointcut 标签对应一个 AspectJExpressionPointcut
- pointcutDefinition = createPointcutDefinition(expression);
- pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
- // 将配置 id 作为 beanName,注册创建的 BeanDefinition,不存在 id,会生成一个 beanName 之后,进行注册
- String pointcutBeanName = id;
- if (StringUtils.hasText(pointcutBeanName)) {
- parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
- }
- else {
- pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
- }
- parserContext.registerComponent(
- new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
- }
- finally {
- this.parseState.pop();
- }
- return pointcutDefinition;
- }
- // 创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition
- protected AbstractBeanDefinition createPointcutDefinition(String expression) {
- RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
- beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
- beanDefinition.setSynthetic(true);
- beanDefinition.getPropertyValues().add(EXPRESSION, expression);
- return beanDefinition;
- }
复制代码 解析 pointcut 标签目的,就是创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition 进行注册。我们知道,AspectJExpressionPointcut 是连接 spring 和 AspectJ 的桥梁,必须需要一个切入点表达式,以是可以看到为注册的 BeanDefinition 设置了一个 expression 属性。
advisor
- // ConfigBeanDefinitionParser
- private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
- // advisor --> BeanDefinition
- AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
- String id = advisorElement.getAttribute(ID);
- try {
- this.parseState.push(new AdvisorEntry(id));
- // 注册
- String advisorBeanName = id;
- if (StringUtils.hasText(advisorBeanName)) {
- parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
- }
- else {
- advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
- }
-
- // 解析 advisor 标签下的 pointcut 属性,为 advisorDef 设置属性
- Object pointcut = parsePointcutProperty(advisorElement, parserContext);
- if (pointcut instanceof BeanDefinition) {
- advisorDef.getPropertyValues().add(POINTCUT, pointcut);
- parserContext.registerComponent(
- new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
- }
- else if (pointcut instanceof String) {
- advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
- parserContext.registerComponent(
- new AdvisorComponentDefinition(advisorBeanName, advisorDef));
- }
- }
- finally {
- this.parseState.pop();
- }
- }
- private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
- RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
- advisorDefinition.setSource(parserContext.extractSource(advisorElement));
- // advice-ref,必须存在,不存在报错
- String adviceRef = advisorElement.getAttribute(ADVICE_REF);
- if (!StringUtils.hasText(adviceRef)) {
- parserContext.getReaderContext().error(
- "'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
- }
- else {
- advisorDefinition.getPropertyValues().add(
- ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
- }
- // order
- if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
- advisorDefinition.getPropertyValues().add(
- ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
- }
- return advisorDefinition;
- }
- @Nullable
- private Object parsePointcutProperty(Element element, ParserContext parserContext) {
- // pointcut 和 pointcut-ref 只能存在一个
- if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
- parserContext.getReaderContext().error(
- "Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
- element, this.parseState.snapshot());
- return null;
- }
- else if (element.hasAttribute(POINTCUT)) {
- // pointcut 直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式
- String expression = element.getAttribute(POINTCUT);
- AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
- pointcutDefinition.setSource(parserContext.extractSource(element));
- return pointcutDefinition;
- }
- else if (element.hasAttribute(POINTCUT_REF)) {
- String pointcutRef = element.getAttribute(POINTCUT_REF);
- if (!StringUtils.hasText(pointcutRef)) {
- parserContext.getReaderContext().error(
- "'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
- return null;
- }
- return pointcutRef;
- }
- else {
- parserContext.getReaderContext().error(
- "Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
- element, this.parseState.snapshot());
- return null;
- }
- }
复制代码 创建 beanClass 为 DefaultBeanFactoryPointcutAdvisor 的 BeanDefinition,之后解析 advice-ref、pointcut/pointcut-ref、order 等属性,设置 propertyValues,完成 BeanDefinition 的注册。
aspect
- // ConfigBeanDefinitionParser
- private void parseAspect(Element aspectElement, ParserContext parserContext) {
- // 获取 id 和 ref 属性
- String aspectId = aspectElement.getAttribute(ID);
- String aspectName = aspectElement.getAttribute(REF);
- try {
- this.parseState.push(new AspectEntry(aspectId, aspectName));
- List<BeanDefinition> beanDefinitions = new ArrayList<>();
- List<BeanReference> beanReferences = new ArrayList<>();
- // 处理子标签 declare-parents
- List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
- for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
- Element declareParentsElement = declareParents.get(i);
- beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
- }
- // We have to parse "advice" and all the advice kinds in one loop, to get the
- // ordering semantics right.
- NodeList nodeList = aspectElement.getChildNodes();
- boolean adviceFoundAlready = false;
- // 遍历子节点
- for (int i = 0; i < nodeList.getLength(); i++) {
- Node node = nodeList.item(i);
- // 判断是否是通知节点,只有是通知节点才处理
- if (isAdviceNode(node, parserContext)) {
- // 依赖的切面类只处理一次
- if (!adviceFoundAlready) {
- adviceFoundAlready = true;
- // 必须存在切面类,不存在报错
- if (!StringUtils.hasText(aspectName)) {
- parserContext.getReaderContext().error(
- "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
- aspectElement, this.parseState.snapshot());
- return;
- }
- // 作为依赖的 bean 存在
- beanReferences.add(new RuntimeBeanReference(aspectName));
- }
- // 一个通知标签封装一个 Advisor,之后将这个 Advisor 对应的 BeanDefinition 注册到 BeanFactory
- AbstractBeanDefinition advisorDefinition = parseAdvice(
- aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
- beanDefinitions.add(advisorDefinition);
- }
- }
- AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
- aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
- parserContext.pushContainingComponent(aspectComponentDefinition);
- // aop:aspect 下 pointcut 子标签,作用和 aop:config 标签下 pointcut 子标签一致
- List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
- for (Element pointcutElement : pointcuts) {
- parsePointcut(pointcutElement, parserContext);
- }
- parserContext.popAndRegisterContainingComponent();
- }
- finally {
- this.parseState.pop();
- }
- }
- // 是 advice 节点,五种通知对应五个标签
- private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
- if (!(aNode instanceof Element)) {
- return false;
- }
- else {
- String name = parserContext.getDelegate().getLocalName(aNode);
- return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
- AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
- }
- }
- private AbstractBeanDefinition parseAdvice(
- String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
- List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
- try {
- this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
- // create the method factory bean
- // method --> BeanDefinition
- RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
- methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
- methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
- methodDefinition.setSynthetic(true);
- // create instance factory definition
- // 切面实例工厂
- RootBeanDefinition aspectFactoryDef =
- new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
- aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
- aspectFactoryDef.setSynthetic(true);
- // register the pointcut
- // 封装通知 advice --> BeanDefinition
- AbstractBeanDefinition adviceDef = createAdviceDefinition(
- adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
- beanDefinitions, beanReferences);
- // configure the advisor
- // 配置 advisor,一个 advice 对应一个 advisor
- RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
- advisorDefinition.setSource(parserContext.extractSource(adviceElement));
- advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
- // advisor order
- if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
- advisorDefinition.getPropertyValues().add(
- ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
- }
- // register the final advisor
- // 注册 advisor
- parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
- return advisorDefinition;
- }
- finally {
- this.parseState.pop();
- }
- }
- private AbstractBeanDefinition createAdviceDefinition(
- Element adviceElement, ParserContext parserContext, String aspectName, int order,
- RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
- List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
- // AspectJ 一种通知类型适配 spring 中一种通知类型
- RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
- adviceDefinition.setSource(parserContext.extractSource(adviceElement));
- // 添加属性
- adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
- adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
- if (adviceElement.hasAttribute(RETURNING)) {
- adviceDefinition.getPropertyValues().add(
- RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
- }
- if (adviceElement.hasAttribute(THROWING)) {
- adviceDefinition.getPropertyValues().add(
- THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
- }
- if (adviceElement.hasAttribute(ARG_NAMES)) {
- adviceDefinition.getPropertyValues().add(
- ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
- }
- // 构造参数,每一个 AspectJXXXAdvice 构造方法都需要三个参数
- ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
- cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
- // 切点
- Object pointcut = parsePointcutProperty(adviceElement, parserContext);
- if (pointcut instanceof BeanDefinition) {
- cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
- beanDefinitions.add((BeanDefinition) pointcut);
- }
- else if (pointcut instanceof String) {
- RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
- cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
- beanReferences.add(pointcutRef);
- }
- // 切面实例工厂
- cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
- return adviceDefinition;
- }
- private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
- String elementName = parserContext.getDelegate().getLocalName(adviceElement);
- if (BEFORE.equals(elementName)) {
- return AspectJMethodBeforeAdvice.class;
- }
- else if (AFTER.equals(elementName)) {
- return AspectJAfterAdvice.class;
- }
- else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
- return AspectJAfterReturningAdvice.class;
- }
- else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
- return AspectJAfterThrowingAdvice.class;
- }
- else if (AROUND.equals(elementName)) {
- return AspectJAroundAdvice.class;
- }
- else {
- throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
- }
- }
- // 前置通知
- public AspectJMethodBeforeAdvice(
- Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
- super(aspectJBeforeAdviceMethod, pointcut, aif);
- }
- public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
- Assert.notNull(advice, "Advice must not be null");
- this.advice = advice;
- this.pointcut = advice.buildSafePointcut();
- }
复制代码 实在就是解析各种通知标签,之后封装 BeanDefinition,注册到 BeanFactory。一个通知对应一个 Advisor。
完成这些标签解析之后,也就在 BeanFactory 中注册了所有的 Advisor。
主动署理生成器的实例化
在 AbstractApplicationContext#refresh 中实行 registerBeanPostProcessors 时,完成 AspectJAwareAdvisorAutoProxyCreator 的实例化。
- // AbstractAdvisorAutoProxyCreator
- @Override
- public void setBeanFactory(BeanFactory beanFactory) {
- // 父类 AbstractAutoProxyCreator
- super.setBeanFactory(beanFactory);
- if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
- throw new IllegalArgumentException(
- "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
- }
- initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
- }
- protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
- // 初始化赋值
- this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
- }
复制代码 在初始化时,进行了相关字段的赋值。
AspectJAwareAdvisorAutoProxyCreator 继续 AbstractAutoProxyCreator,以是署理的生成也遵照 spring 中定义的逻辑。
至于前面解析的各种标签注册的 BeanDefinition,则在 AbstractApplicationContext#finishBeanFactoryInitialization 时完成实例对象的创建。
署理的实现
BeanFactory 中所有 Advisor 的实例化
在业务 bean 的实例化过程中,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,就会实行到 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法中,判断业务 bean 是否需要署理。
- @Override
- public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
- Object cacheKey = getCacheKey(beanClass, beanName);
- if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
- if (this.advisedBeans.containsKey(cacheKey)) {
- return null;
- }
- if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
- this.advisedBeans.put(cacheKey, Boolean.FALSE);
- return null;
- }
- }
- // Create proxy here if we have a custom TargetSource.
- // Suppresses unnecessary default instantiation of the target bean:
- // The TargetSource will handle target instances in a custom fashion.
- TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
- if (targetSource != null) {
- if (StringUtils.hasLength(beanName)) {
- this.targetSourcedBeans.add(beanName);
- }
- Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
- Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
- this.proxyTypes.put(cacheKey, proxy.getClass());
- return proxy;
- }
- return null;
- }
复制代码 其中,AspectJAwareAdvisorAutoProxyCreator 重写了 shouldSkip 方法。
- @Override
- protected boolean shouldSkip(Class<?> beanClass, String beanName) {
- // 获取所有候选 Advisor
- List<Advisor> candidateAdvisors = findCandidateAdvisors();
- // advisor 中 aspectName 如果和带创建的 beanName 一致,表明正在创建切面类实例,返回 true,表示切面类不需要代理
- for (Advisor advisor : candidateAdvisors) {
- if (advisor instanceof AspectJPointcutAdvisor &&
- ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
- return true;
- }
- }
- return super.shouldSkip(beanClass, beanName);
- }
复制代码 主要来看下 findCandidateAdvisors 这个方法。
- // AbstractAdvisorAutoProxyCreator
- protected List<Advisor> findCandidateAdvisors() {
- Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
- return this.advisorRetrievalHelper.findAdvisorBeans();
- }
复制代码 在 AspectJAwareAdvisorAutoProxyCreator 实例对象创建时,已经完成了 advisorRetrievalHelper 的创建赋值,是一个工具类 BeanFactoryAdvisorRetrievalHelper。
- // BeanFactoryAdvisorRetrievalHelper
- public List<Advisor> findAdvisorBeans() {
- // Determine list of advisor bean names, if not cached already.
- String[] advisorNames = this.cachedAdvisorBeanNames;
- if (advisorNames == null) {
- // Do not initialize FactoryBeans here: We need to leave all regular beans
- // uninitialized to let the auto-proxy creator apply to them!
- // 获取注册的所有 Advisor 对应的名称集合
- advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
- this.beanFactory, Advisor.class, true, false);
- this.cachedAdvisorBeanNames = advisorNames;
- }
- if (advisorNames.length == 0) {
- return new ArrayList<>();
- }
- List<Advisor> advisors = new ArrayList<>();
- for (String name : advisorNames) {
- if (isEligibleBean(name)) {
- if (this.beanFactory.isCurrentlyInCreation(name)) {
- if (logger.isTraceEnabled()) {
- logger.trace("Skipping currently created advisor '" + name + "'");
- }
- }
- else {
- try {
- // 对象未创建则在此时进行创建
- advisors.add(this.beanFactory.getBean(name, Advisor.class));
- }
- catch (BeanCreationException ex) {
- ...
- // 抛出异常
- }
- }
- }
- }
- return advisors;
- }
复制代码 bean 的创建过程,此处不再赘述。有几点需要留意:
- 一个 pointcut 可以被多个 advisor 和 aspect 下通知子标签引用,即可以在一个切入点应用多个顾问和通知,pointcut 对应的 beanClass 为 AspectJExpressionPointcut,创建 BeanDefinition 时设置 scope 为 prototype,以是每一个对 AspectJExpressionPointcut 的引用,都会创建一个新的对象。
- aspect 标签下各个通知子标签对应的 Advisor 为 AspectJPointcutAdvisor,持有的 Advice 为通知子标签封装的 AspectJXXXAdvice。
- AspectJPointcutAdvisor 构造方法注入时,需要 AbstractAspectJAdvice,而每一个 AspectJXXXAdvice 构造方法都需要三个参数,通报给父类 AbstractAspectJAdvice。
- public AbstractAspectJAdvice(
- Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
- Assert.notNull(aspectJAdviceMethod, "Advice method must not be null");
- this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
- this.methodName = aspectJAdviceMethod.getName();
- this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
- this.aspectJAdviceMethod = aspectJAdviceMethod;
- this.pointcut = pointcut;
- this.aspectInstanceFactory = aspectInstanceFactory;
- }
复制代码 第一个参数,需要的是一个切面类中的通知方法,在 aspect 标签解析时,针对通知标签,封装一个 beanClass 为 MethodLocatingFactoryBean 的 BeanDefinition。当解析第一个参数时,会实行 MethodLocatingFactoryBean 的创建。
- // MethodLocatingFactoryBean
- @Override
- public void setBeanFactory(BeanFactory beanFactory) {
- if (!StringUtils.hasText(this.targetBeanName)) {
- throw new IllegalArgumentException("Property 'targetBeanName' is required");
- }
- if (!StringUtils.hasText(this.methodName)) {
- throw new IllegalArgumentException("Property 'methodName' is required");
- }
- Class<?> beanClass = beanFactory.getType(this.targetBeanName);
- if (beanClass == null) {
- throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName + "'");
- }
- this.method = BeanUtils.resolveSignature(this.methodName, beanClass);
- if (this.method == null) {
- throw new IllegalArgumentException("Unable to locate method [" + this.methodName +
- "] on bean [" + this.targetBeanName + "]");
- }
- }
复制代码 会在 MethodLocatingFactoryBean 对象初始化时,完成目的通知方法的确定。
- // BeanUtils 根据方法名称从指定 clazz 中确定 method
- @Nullable
- public static Method resolveSignature(String signature, Class<?> clazz) {
- Assert.hasText(signature, "'signature' must not be empty");
- Assert.notNull(clazz, "Class must not be null");
- int startParen = signature.indexOf('(');
- int endParen = signature.indexOf(')');
- if (startParen > -1 && endParen == -1) {
- throw new IllegalArgumentException("Invalid method signature '" + signature +
- "': expected closing ')' for args list");
- }
- else if (startParen == -1 && endParen > -1) {
- throw new IllegalArgumentException("Invalid method signature '" + signature +
- "': expected opening '(' for args list");
- }
- else if (startParen == -1) {
- // 不指定参数类型
- return findMethodWithMinimalParameters(clazz, signature);
- }
- else {
- // 方法名
- String methodName = signature.substring(0, startParen);
- // 逗号分割,获取参数类型数组
- String[] parameterTypeNames =
- StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
- Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
- for (int i = 0; i < parameterTypeNames.length; i++) {
- String parameterTypeName = parameterTypeNames[i].trim();
- try {
- // 加载类型,保证配置的每一个类型的正确性
- parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
- }
- catch (Throwable ex) {
- throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +
- parameterTypeName + "] for argument " + i + ". Root cause: " + ex);
- }
- }
- // 根据类型获取指定方法
- return findMethod(clazz, methodName, parameterTypes);
- }
- }
- @Nullable
- public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)
- throws IllegalArgumentException {
- // 实际上 clazz.getMethods() 已经包含了当前类及所有父类中 public、protected 修饰的方法,但不包含 private 方法
- Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
- if (targetMethod == null) {
- // 当目标方法为 private 修饰时,通过以下方法查找
- targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
- }
- return targetMethod;
- }
- @Nullable
- public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)
- throws IllegalArgumentException {
- Method targetMethod = null;
- int numMethodsFoundWithCurrentMinimumArgs = 0;
- for (Method method : methods) {
- // 比较参数名称
- if (method.getName().equals(methodName)) {
- int numParams = method.getParameterCount();
- // 将参数长度最短的方法作为 targetMethod 返回
- if (targetMethod == null || numParams < targetMethod.getParameterCount()) {
- targetMethod = method;
- numMethodsFoundWithCurrentMinimumArgs = 1;
- }
- else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
- // 用常规方法覆盖桥接方法
- if (targetMethod.isBridge()) {
- // Prefer regular method over bridge...
- targetMethod = method;
- }
- else {
- // Additional candidate with same length
- // 当存在方法重写或重载时,发现了两个名称和参数长度一样的方法,数量自增
- numMethodsFoundWithCurrentMinimumArgs++;
- }
- }
- }
- }
- // 存在方法重写时抛出异常,即不确定使用的是子类方法还是父类方法
- // 重载时也会存在,方法名称一致,参数长度一致,但类型不一致,此处只校验长度,无法确定是哪一个方法
- if (numMethodsFoundWithCurrentMinimumArgs > 1) {
- throw new IllegalArgumentException("Cannot resolve method '" + methodName +
- "' to a unique method. Attempted to resolve to overloaded method with " +
- "the least number of parameters but there were " +
- numMethodsFoundWithCurrentMinimumArgs + " candidates.");
- }
- return targetMethod;
- }
- // 查找当前类,并递归父类,返回 public、protected、private 修饰方法
- @Nullable
- public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)
- throws IllegalArgumentException {
- Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
- if (targetMethod == null && clazz.getSuperclass() != null) {
- targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
- }
- return targetMethod;
- }
- @Nullable
- public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
- try {
- return clazz.getMethod(methodName, paramTypes);
- }
- catch (NoSuchMethodException ex) {
- return findDeclaredMethod(clazz, methodName, paramTypes);
- }
- }
复制代码 上面的代码解释了在切面类中确定目的通知方法的实现,主要逻辑如下:
- 不指定方法参数类型时,按最短参数长度查找,指定参数类型时,按参数类型查找,也就是说,xml 中配置 methodName 时,可以是 methodName(argType1,argType2) 这种配置原型。
- 不指定方法参数类型时,按最短参数长度查找,若存在方法重写和方法重载导致的多个方法名称和参数长度一致,会抛出异常
- private 修饰的方法也可以被找到而作为目的通知方法
MethodLocatingFactoryBean 创建完成之后,由于是 FactoryBean 子类,会调用 this.beanFactory.getObjectFromFactoryBean 获取真正的对象。
- // MethodLocatingFactoryBean
- @Override
- @Nullable
- public Method getObject() throws Exception {
- return this.method;
- }
复制代码 可以看到,获取的 Method 对象就是上面在切面类中确定的方法。这也解释了为什么 AspectJXXXAdvice 构造方法第一个参数类型为 Method,而解析标签时却配置了一个 MethodLocatingFactoryBean 工厂。
接下来看第二个构造参数,需要的是一个 AspectJExpressionPointcut,通知子标签支持 pointcut 和 pointcut-ref 两种方式来定义切入点。
解析标签时,假如是 pointcut,直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式字符串;假如是 pointcut-ref,表明是一个引用类型,引用的 aop:pointcut 子标签已经封装成了 BeanDefinition,此处返回名称字符串封装一个 RuntimeBeanReference。以是通报给第二个构造参数的,要么是一个 BeanDefinition,要么是一个 RuntimeBeanReference。
在 ConstructorResolver#resolveConstructorArguments 方法中,解析构造参数,不管是 BeanDefinition,还是 RuntimeBeanReference 引用,由于背后定义 BeanDefinition 时设置的 scope 都是 prototype,以是此处都会创建一个新的对象。
第三个参数,需要一个 AspectInstanceFactory,即切面实例工厂,传入的是一个 beanClass 为 SimpleBeanFactoryAwareAspectInstanceFactory 的 BeanDefinition,而这个 SimpleBeanFactoryAwareAspectInstanceFactory 就是 AspectInstanceFactory 的实现类,在此时完成实例化对象创建。
事实上,aspect 下的通知子标签,一个通知对应一个 Advisor,即 AspectJPointcutAdvisor,由于存在构造参数,采用构造方法实例化,此时又对依赖的构造参数 AbstractAspectJAdvice 进行了实例化创建,这个 AbstractAspectJAdvice 又存在构造参数,继续采用 AbstractAutowireCapableBeanFactory#autowireConstructor 进行实例化对象创建。
创建完 AspectJXXXAdvice,将其作为构造参数,完成 AspectJPointcutAdvisor 的实例化。
- public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
- Assert.notNull(advice, "Advice must not be null");
- this.advice = advice;
- this.pointcut = advice.buildSafePointcut();
- }
复制代码 在构造方法中实行了 advice.buildSafePointcut(),这是在做什么呢?继续向下看。
- // AbstractAspectJAdvice
- public final Pointcut buildSafePointcut() {
- // AspectJExpressionPointcut
- Pointcut pc = getPointcut();
- MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
- new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
- // 组合
- return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
- }
- // AspectJExpressionPointcut
- @Override
- public MethodMatcher getMethodMatcher() {
- obtainPointcutExpression();
- return this;
- }
- // AspectJExpressionPointcut
- private PointcutExpression obtainPointcutExpression() {
- if (getExpression() == null) {
- throw new IllegalStateException("Must set property 'expression' before attempting to match");
- }
- if (this.pointcutExpression == null) {
- this.pointcutClassLoader = determinePointcutClassLoader();
- // 解析切入点表达式,创建 PointcutExpressionImpl 返回
- this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
- }
- return this.pointcutExpression;
- }
- public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) {
- return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
- new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
- }
- public IntersectionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
- super(mm1, mm2);
- }
复制代码 pc.getMethodMatcher() 时完成了 pc 中切入点表达式的解析,创建了一个 org.aspectj.internal.lang.reflect.PointcutExpressionImpl 对象赋值给 AspectJExpressionPointcut 中的 pointcutExpression 字段。之后创建一个 IntersectionIntroductionAwareMethodMatcher 对象作为 safeMethodMatcher,之后将 safeMethodMatcher 和 pc.getClassFilter() 返回的 AspectJExpressionPointcut 组合起来,封装一个 ComposablePointcut 返回。
完成 AspectJPointcutAdvisor 的对象创建之后,将其加入 advisors 集合,之后将集合返回,作为候选的 Advisor,即 candidateAdvisors。
再回到 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法中,遍历 candidateAdvisors,advisor 中 aspectName 假如和当前创建的 beanName 一致,表明正在创建切面类实例,返回 true,即需要跳过。之后在 AbstractAutoProxyCreator#postProcessBeforeInstantiation 中,针对当前 beanClass 和 beanName 生成的 cacheKey,标记为 false。
署理对象的创建
完成目的类的实例化之后,在进行初始化时,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,会实行到 AbstractAutoProxyCreator#postProcessAfterInitialization --> wrapIfNecessary。
- protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
- if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
- return bean;
- }
- if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
- return bean;
- }
- if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
- this.advisedBeans.put(cacheKey, Boolean.FALSE);
- return bean;
- }
- // Create proxy if we have advice.
- Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
- if (specificInterceptors != DO_NOT_PROXY) {
- this.advisedBeans.put(cacheKey, Boolean.TRUE);
- Object proxy = createProxy(
- bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
- this.proxyTypes.put(cacheKey, proxy.getClass());
- return proxy;
- }
- this.advisedBeans.put(cacheKey, Boolean.FALSE);
- return bean;
- }
复制代码 这是 spring 创建署理的模板。先来看对 Advisor 的过滤,找到当前目的类需要的 Advisor。
- // AbstractAdvisorAutoProxyCreator
- @Override
- @Nullable
- protected Object[] getAdvicesAndAdvisorsForBean(
- Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
- List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
- if (advisors.isEmpty()) {
- return DO_NOT_PROXY;
- }
- return advisors.toArray();
- }
- // AbstractAdvisorAutoProxyCreator
- protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
- // 获取所有 BeanFaactory 中定义的 Advisor,前面创建过,所以此处获取很快
- List<Advisor> candidateAdvisors = findCandidateAdvisors();
- // 筛选
- List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
- // 扩展
- extendAdvisors(eligibleAdvisors);
- // 排序
- if (!eligibleAdvisors.isEmpty()) {
- eligibleAdvisors = sortAdvisors(eligibleAdvisors);
- }
- return eligibleAdvisors;
- }
- // AopUtils
- public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
- if (candidateAdvisors.isEmpty()) {
- return candidateAdvisors;
- }
- List<Advisor> eligibleAdvisors = new ArrayList<>();
- for (Advisor candidate : candidateAdvisors) {
- if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
- eligibleAdvisors.add(candidate);
- }
- }
- 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;
- }
- 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) {
- // 对于 Advisor 为 DefaultBeanFactoryPointcutAdvisor,在进行 canApply 时执行 pc.getClassFilter 完成切入点表达式的解析
- PointcutAdvisor pca = (PointcutAdvisor) advisor;
- return canApply(pca.getPointcut(), targetClass, hasIntroductions);
- }
- else {
- // It doesn't have a pointcut so we assume it applies.
- return true;
- }
- }
- 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<>();
- 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;
- }
复制代码 这些都是 spring 中实现 AOP 的通用代码,区别就在于差异的 org.springframework.aop.PointcutAdvisor,持有的 org.springframework.aop.Pointcut 差异,差异的 org.springframework.aop.Pointcut,持有的 ClassFilter 和 MethodMatcher 差异。实现AopUtils#canApply 时,使用每个 org.springframework.aop.Pointcut 中 ClassFilter 和 MethodMatcher 中定义的 matches 方法进行匹配。以是也可以按照自己定义的规则,对 org.springframework.aop.Pointcut 进行扩展。
找到合格的 Advisor 之后,调用 AbstractAdvisorAutoProxyCreator#extendAdvisors,而 AspectJAwareAdvisorAutoProxyCreator 对此方法进行了重写。
- @Override
- protected void extendAdvisors(List<Advisor> candidateAdvisors) {
- AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
- }
- public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
- // Don't add advisors to an empty list; may indicate that proxying is just not required
- if (!advisors.isEmpty()) {
- boolean foundAspectJAdvice = false;
- for (Advisor advisor : advisors) {
- // Be careful not to get the Advice without a guard, as this might eagerly
- // instantiate a non-singleton AspectJ aspect...
- if (isAspectJAdvice(advisor)) {
- foundAspectJAdvice = true;
- break;
- }
- }
- if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
- advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
- return true;
- }
- }
- return false;
- }
- private static boolean isAspectJAdvice(Advisor advisor) {
- return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
- advisor.getAdvice() instanceof AbstractAspectJAdvice ||
- (advisor instanceof PointcutAdvisor &&
- ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
- }
复制代码 判定是否 Advisor 集合中存在 AspectJAdvice,存在,在 Advisor 集合的首位加入 ExposeInvocationInterceptor.ADVISOR。至于为啥要加入这个 Advisor,可以参考 spring 中 AspectJ 基于注解的实现分析。
此处有一点要留意,就是假如 Advisor 为 DefaultBeanFactoryPointcutAdvisor,此前虽然进行了实例化,但其中依赖的 Advice 并未进行实例化,此时实行 advisor.getAdvice() 会对依赖的 Advice 完成实例化。
扩展完 eligibleAdvisors 之后,对 eligibleAdvisors 按照优先级进行排序。详细的排序过程可以参考AspectJ 下 Advisor 的排序过程。
排序之后,将集合处置惩罚成数组返回,赋值给 specificInterceptors。
之后调用 AbstractAutoProxyCreator#createProxy 创建署理,此时 AbstractAutoProxyCreator 就是 AspectJAwareAdvisorAutoProxyCreator,将 <aop:config> 标签中定义的 proxy-target-class 和 expose-proxy 两个属性又通报给 ProxyFactory。
- // AbstractAutoProxyCreator
- protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
- @Nullable Object[] specificInterceptors, TargetSource targetSource) {
- if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
- AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
- }
- ProxyFactory proxyFactory = new ProxyFactory();
- proxyFactory.copyFrom(this);
- if (proxyFactory.isProxyTargetClass()) {
- // Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
- if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
- // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
- for (Class<?> ifc : beanClass.getInterfaces()) {
- proxyFactory.addInterface(ifc);
- }
- }
- }
- else {
- // No proxyTargetClass flag enforced, let's apply our default checks...
- if (shouldProxyTargetClass(beanClass, beanName)) {
- proxyFactory.setProxyTargetClass(true);
- }
- else {
- evaluateProxyInterfaces(beanClass, proxyFactory);
- }
- }
- Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
- proxyFactory.addAdvisors(advisors);
- proxyFactory.setTargetSource(targetSource);
- customizeProxyFactory(proxyFactory);
- proxyFactory.setFrozen(this.freezeProxy);
- // true
- if (advisorsPreFiltered()) {
- proxyFactory.setPreFiltered(true);
- }
- // Use original ClassLoader if bean class not locally loaded in overriding class loader
- ClassLoader classLoader = getProxyClassLoader();
- if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
- classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
- }
- return proxyFactory.getProxy(classLoader);
- }
复制代码 创建署理的这一步,都是遵照 spring 中的定义来实现。
方法调用
雷同处置惩罚的,此处不在赘述,可以参考spring 中主动署理生成器的实现。
有一点需要留意,就是调用 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法时,遍历 advisors。前面介绍过,aspect 标签下通知对应的 Advisor 为 AspectJPointcutAdvisor,在实行有参构造时,封装的 pointcut 为 ComposablePointcut。
两个字段,主要关注 methodMatcher,通过前面的介绍,这个 methodMatcher 为 MethodMatchers$IntersectionIntroductionAwareMethodMatcher。 mm1 为定义的 AbstractAspectJAdvice$AdviceExcludingMethodMatcher,mm2 为 pc.getMethodMatcher(),也就是 Pointcut 中持有的 MethodMatcher。
此时调用 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); 得到 MethodMatchers$IntersectionIntroductionAwareMethodMatcher,接着调用其 matches 方法。
- // IntersectionIntroductionAwareMethodMatcher
- @Override
- public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
- return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
- MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
- }
- // MethodMatches
- public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
- Assert.notNull(mm, "MethodMatcher must not be null");
- return (mm instanceof IntroductionAwareMethodMatcher ?
- ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
- mm.matches(method, targetClass));
- }
- // AdviceExcludingMethodMatcher
- @Override
- public boolean matches(Method method, Class<?> targetClass) {
- return !this.adviceMethod.equals(method);
- }
复制代码 AdviceExcludingMethodMatcher 并不是 IntroductionAwareMethodMatcher 实例,调用 AdviceExcludingMethodMatcher#matches 方法判定目的方法是否是通知方法,不是返回 true。以是主要的判断还是基于 mm2,mm2 为 AspectJExpressionPointcut。
- // AspectJExpressionPointcut
- @Override
- public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
- obtainPointcutExpression();
- // org.aspectj.weaver.tools.ShadowMatch
- ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
- // Special handling for this, target, @this, @target, @annotation
- // in Spring - we can optimize since we know we have exactly this class,
- // and there will never be matching subclass at runtime.
- if (shadowMatch.alwaysMatches()) {
- return true;
- }
- else if (shadowMatch.neverMatches()) {
- return false;
- }
- else {
- // the maybe case
- if (hasIntroductions) {
- return true;
- }
- // A match test returned maybe - if there are any subtype sensitive variables
- // involved in the test (this, target, at_this, at_target, at_annotation) then
- // we say this is not a match as in Spring there will never be a different
- // runtime subtype.
- RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
- return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
- }
- }
复制代码 进入 AspectJExpressionPointcut#matches,委托给 AspectJ 进行切入点表达式和目的方法的匹配。
之后将筛选出的 Advisor,根据持有的通知类型的差异,适配成差异的 org.aopalliance.intercept.MethodInterceptor,封装成拦截器链。接着封装 MethodInvocation,调用 proceed 方法。
总结
介绍完了 AspectJ 下基于注解和 XML 的 AOP实现。现在我们来总结一下这两者的区别。
标签解析
实现方式 | 标签解析器 | 注解 | AspectJAutoProxyBeanDefinitionParser | XML | ConfigBeanDefinitionParser | 署理生成器
实现方式 | 署理生成器 | 注解 | AnnotationAwareAspectJAutoProxyCreator | XML | AspectJAwareAdvisorAutoProxyCreator | Advisor 的创建
实现方式 | 署理生成器 | 注解 | AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors | XML | AbstractAdvisorAutoProxyCreator#findCandidateAdvisors | 注解方式下,AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors 方法,通过找到持有 @Aspect 注解的类,接着获取类中定义的通知方法,将其封装成 Advisor。
而 XML 模式下,由于在 XML 中已经定义了切面类、切入点、通知和顾问,以是会采用 spring 中定义的通用模板来获取 Advisor。
Advisor 的类型
实现方式 | Advisor 类型 | 注解 | InstantiationModelAwarePointcutAdvisorImpl | XML | advisor 标签对应 DefaultBeanFactoryPointcutAdvisor | aspect 下通知子标签对应 AspectJPointcutAdvisor | 除了这些显式的差异,还有一个隐式的差异点,就是 AspectJ 解析 expression 的时机。
实现方式 | Advisor 类型 | AspectJ 解析 expression 的时机 | 注解 | InstantiationModelAwarePointcutAdvisorImpl | AbstractAdvisorAutoProxyCreator下findEligibleAdvisors 方法中对获取的 candidateAdvisors 进行筛选时完成 | XML | DefaultBeanFactoryPointcutAdvisor | AspectJPointcutAdvisor | 有参构造方法实例化,实行 buildSafePointcut 方法时完成 | 下面我们来看下注解和 XML 这两种实现方式的共同点。
Advisor 的创建时机,都是在实行 AbstractAutoProxyCreator#postProcessBeforeInstantiation ,第一次调用 shouldSkip 方法时完成的,并将创建的 Advisor 实例对象加入到了 DefaultListableBeanFactory 的父类 DefaultSingletonBeanRegistry 中的 singletonObjects,之后获取 Advisor 时直接从 singletonObjects 获取。
业务 bean 署理对象的创建和方法调用,完全遵从 spring 中定义的 AOP 实现。至于方法匹配,则通过 AspectJExpressionPointcut 这个纽带,完全委托给了 AspectJ 这个框架去实现。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |