Пользовательская аннотация весенней загрузки AOP с ленточным клиентом, блокирующим вызов API с возвратом 1

У меня очень плохой опыт работы с лентой/эврикой, поэтому простите меня, если это глупый вопрос:

У меня есть два разных микросервиса, оба подключены к серверу обнаружения, первый вызывает второй, используя пользовательскую аннотацию, которая отправляет запрос с использованием шаблона отдыха. Имя пользовательской аннотации: PreHasAuthority.

Контроллер:

    @PreHasAuthority(value="[0].getProject()+'.requirements.update'")
    @PostMapping(CREATE_UPDATE_REQUIREMENT)
    public ResponseEntity<?> createUpdateRequirement(@Valid @RequestBody RequirementDTO requirementDTO
, HttpServletRequest request, HttpServletResponse response) {
        
        return requirementService.createUpdateRequirement(requirementDTO, request, response);
    }

Интерфейс аннотации:


import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreHasAuthority {

    String value();
    
}

Реализация аннотации:

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;

import netcomgroup.eu.service.AuthenticationService;

@Aspect
@Component
public class PreHasAuthorityServiceAspect {

    @Autowired
    private AuthenticationService authenticationService;
    
    @Around(value = "@annotation(PreHasAuthority)")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        PreHasAuthority preHasAuthority = method.getAnnotation(PreHasAuthority.class);
        
        Object[] args = joinPoint.getArgs();
        String permission = preHasAuthority.value();
        ExpressionParser elParser = new SpelExpressionParser();
        Expression expression = elParser.parseExpression(permission);
        String per = (String) expression.getValue(args);
        
        String token =null;
        for(Object o : args) {
            if(o instanceof HttpServletRequest) {
                HttpServletRequest request = (HttpServletRequest)o;
                token=request.getHeader("X-Auth");
                break;
            }
        }
        
        if(token==null) {
            throw new IllegalArgumentException("Token not found");
        }
        
        boolean hasPerm = authenticationService.checkPermission(per,token);
        
        if(!hasPerm) 
            throw new Exception("Not Authorized");
    }
}

Конфигурация моей ленты

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

public class RibbonConfiguration {

    @Autowired
    IClientConfig config;

    @Bean
    public IRule ribbonRule(IClientConfig config) {
        return new RoundRobinRule();
    }
}

Конфигурация Eureka в свойствах приложения

#Eureka config
eureka.client.serviceUrl.defaultZone= http://${registry.host:localhost}:${registry.port:8761}/eureka/
eureka.client.healthcheck.enabled= true
eureka.instance.leaseRenewalIntervalInSeconds= 10
eureka.instance.leaseExpirationDurationInSeconds= 10

при вызове API от почтальона запрос правильно отправляется второму микросервису, и я уверен, что возврат верен.

После этого запрос останавливается перед входом в метод createUpdateRequirement и возвращает '1' в качестве ответа почтальона. Ошибка сортировки не предусмотрена.

Я предполагаю, что проблема заключается в пользовательской аннотации, потому что, когда я удаляю аннотацию, вызов API работает отлично, но я не могу понять проблему, поскольку мне кажется, что все настроено правильно.


person Peo    schedule 29.10.2020    source источник
comment
Предоставьте трассировку стека ошибок, чтобы нам было легко исследовать эту ситуацию.   -  person marcin.programuje    schedule 29.10.2020
comment
Основная проблема в том, что я не получил ошибки, вызов API просто останавливается перед входом в createUpdateRequirement без всякой причины для меня.   -  person Peo    schedule 30.10.2020
comment
@Peo Вы отлаживали код аспекта, чтобы увидеть, работает ли он должным образом? Метод around может не переходить к методу createUpdateRequirement   -  person R.G    schedule 31.10.2020
comment
да, мой код аспекта работал, как и ожидалось. Как указал Kriegaex, решение состояло в том, чтобы добавить joinpoint.proceed() в метод аспекта для продолжения выполнения. Я также изменил тип возврата соответственно.   -  person Peo    schedule 02.11.2020


Ответы (1)


Ваш @Around совет никогда не вызывает joinPoint.proceed(). Следовательно, перехваченный целевой метод никогда не будет выполнен.

Вторая проблема заключается в том, что ваш метод совета возвращает void, т. е. он никогда не будет соответствовать какому-либо методу, возвращающему другой тип, например методу ResponseEntity<?> createUpdateRequirement(..).

Кроме того, around является зарезервированным ключевым словом в родном синтаксисе AspectJ. Несмотря на то, что он может работать в синтаксисе, основанном на аннотациях, вы должны переименовать свой метод совета во что-то другое, например aroundAdvice или interceptPreHasAuthority - как угодно.

Пожалуйста, прочтите учебник AspectJ или Spring AOP, особенно Глава АОП руководства Spring. ????

person kriegaex    schedule 02.11.2020
comment
Спасибо, joinPoint.proceed() сделал свое дело, большое спасибо! - person Peo; 02.11.2020