Смешать использование BeanNameAutoProxyCreator и AnnotationAwareAspectJAutoProxyCreator для того, чтобы прокси же бин вызывал странную вещь?

Когда я смешиваю, используйте BeanNameAutoProxyCreator и AnnotationAwareAspectJAutoProxyCreator для улучшения (прокси) bean-компонента. Просто как ниже:

public interface DemoProviderService {
  @Dependence
  void success();
}
public class DemoProviderServiceImpl implements DemoProviderService {
  @Resource
  private DemoServiceProxy demoServiceProxy;

  @Override
  public void success() {
      System.out.println("success")
  }
}

 @Aspect
public class DependenceAspect {

  @Around("@annotation(xxx.annotation.Dependence)")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
  }
}


<aop:aspectj-autoproxy/>
<bean id="demoProviderService" class="xxx.DemoProviderServiceImpl"/>
<bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>
            <value>demoProviderService</value>
        </list>
    </property>
    <property name="interceptorNames">
        <list>
            <value>demoMethodInterceptor</value>
        </list>
    </property>
</bean>
<bean id="demoMethodInterceptor" class="xxx.DemoMethodInterceptor"/>
</beans>

Я знаю, что BeanNameAutoProxyCreator и AnnotationAwareAspectJAutoProxyCreator являются подклассами InstantiationAwareBeanPostProcessor. Порядок выполнения нескольких классов BeanPostProcessor является случайным, если вы не используете интерфейс Ordered для управления. Я обнаружил некоторые странные вещи, поскольку разный порядок выполнения двух AutoProxyCreators. Когда BeanNameAutoProxyCreator выполняется первым, AnnotationAwareAspectJAutoProxyCreator не может прокси-bean-компонент demoProviderService. Оба AutoProxyCreators могут прокси-компонент bemo demoProviderService, если вместо этого сначала выполняется AnnotationAwareAspectJAutoProxyCreator. Я читаю исходный код и нахожу код причины, вызывающей странные вещи. Код является следующим: AopUtils.findAdvisorsThatCanApply (андидат Advisors, beanClass);

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        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;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
        checkReadyToMatch();
        Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
        ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);

        // 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 (beanHasIntroductions) {
                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));
        }
    }

private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
        // Avoid lock contention for known Methods through concurrent access...
        ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
        if (shadowMatch == null) {
            synchronized (this.shadowMatchCache) {
                // Not found - now check again with full lock...
                PointcutExpression fallbackExpression = null;
                Method methodToMatch = targetMethod;
                shadowMatch = this.shadowMatchCache.get(targetMethod);
                if (shadowMatch == null) {
                    try {
                        try {
                            shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
                        }
                        catch (ReflectionWorldException ex) {
                            // Failed to introspect target method, probably because it has been loaded
                            // in a special ClassLoader. Let's try the declaring ClassLoader instead...
                            try {
                                fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
                                if (fallbackExpression != null) {
                                    shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
                                }
                            }
                            catch (ReflectionWorldException ex2) {
                                fallbackExpression = null;
                            }
                        }
                        if (shadowMatch == null && targetMethod != originalMethod) {
                            methodToMatch = originalMethod;
                            try {
                                shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
                            }
                            catch (ReflectionWorldException ex3) {
                                // Could neither introspect the target class nor the proxy class ->
                                // let's try the original method's declaring class before we give up...
                                try {
                                    fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
                                    if (fallbackExpression != null) {
                                        shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
                                    }
                                }
                                catch (ReflectionWorldException ex4) {
                                    fallbackExpression = null;
                                }
                            }
                        }
                    }
                    catch (Throwable ex) {
                        // Possibly AspectJ 1.8.10 encountering an invalid signature
                        logger.debug("PointcutExpression matching rejected target method", ex);
                        fallbackExpression = null;
                    }
                    if (shadowMatch == null) {
                        shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
                    }
                    else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
                        shadowMatch = new DefensiveShadowMatch(shadowMatch,
                                fallbackExpression.matchesMethodExecution(methodToMatch));
                    }
                    this.shadowMatchCache.put(targetMethod, shadowMatch);
                }
            }
        }
        return shadowMatch;
    }

Причина в том, что если BeanNameAutoProxyCreator выполняется первым (предположим, BeanNameAutoProxyCreator setProxyTargetClass(true), класс компонента будет сгенерирован заново (имя класса компонента, например DemoProviderServiceImpl$$EnhancerBySpringCGLIB$$6ec1b8b, не будет наследником) и не будет использоваться для пружины. условие соответствия отрезка аспектной точки). Поэтому при выполнении AnnotationAwareAspectJAutoProxyCreator метод getShadowMatch определит совпадение pointcutExpression или нет. targetMethod был расширен с помощью Spring cglib, не будет наследовать аннотацию "Зависимость", поскольку shadowMatch никогда не будет соответствовать выражению pointcut. Я хочу спросить, почему Spring отдает приоритет targetMethod вместо originalMethod для соответствия выражению pointcut? Является ли это ошибкой или основывается на каком-то особом соображении? Я хочу отдавать приоритет originalMethod вместо targetMethod, чтобы избежать сложного поведения. Это нормально?

0 ответов

Другие вопросы по тегам