Смешать использование 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, чтобы избежать сложного поведения. Это нормально?