Spring MVC и AOP: @Pointcuts применяются только для остальных контроллеров, но не для обычных веб-контроллеров
Я работаю с Spring Framework
4.3.3 в веб-среде.
у меня есть @Controller
используется для Web
запросы через Web Browser
который использует, как зависимость другого @Controller
но для Rest
цели. Последнее упомянутое использует @Service
так далее...
Этот подход к "Web" с использованием "Rest" объясняет, как зависимость описывается в Content Negotiation с использованием Spring MVC для Combining Data and Presentation Formats
раздел. Пока здесь для разработки / тестирования и производства работает нормально. Это ценный подход.
Примечание Rest
класс аннотируется @Controller
потому что я работаю с ResponseEntity<?>
а также @ResponseBody
,
Проблема с AOP
Про свою инфраструктуру я имею:
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}
О @Controller
у меня есть эти два класса:
PersonaDeleteOneController
с:deleteOne(@PathVariable String id, Model model)
за@GetMapping
deleteOne(@PathVariable String id, RedirectAttributes redirectAttributes)
за@DeleteMapping
PersonaRestController
deleteOne(@PathVariable String id)
за@DeleteMapping
Эти два класса объявлены в одном и том же пакете с именем:
com.manuel.jordan.controller.persona
У меня есть следующее @Pointcut
:
@Pointcut(value=
"execution(* com.manuel.jordan.controller.*.*Controller.deleteOne(String, ..))
&& args(id) && target(object)")
public void deleteOnePointcut(String id, Object object){}
Тот @Pointcut
используется для следующих советов:
@Before(value="ControllerPointcut.deleteOnePointcut(id, object)")
public void beforeAdviceDeleteOne(String id, Object object){
logger.info("beforeAdviceDeleteOne - @Controller: {} - Method: deleteOne - id: {}", object.getClass().getSimpleName(), id);
}
Когда я выполню Rest
тесты, которые я могу подтвердить через AOP + logging
это печатает следующий образец:
@Controller
(Отдых) ->@Service
->@Repository
Пока здесь все работает так, как ожидается
Когда я выполню Web
тесты, которые я могу подтвердить через AOP + logging
это печатает следующий образец:
@Controller
(Отдых) ->@Service
->@Repository
Что мне нужно или ожидать, это следующее:
@Controller
(Интернет) ->@Controller
(Отдых) ->@Service
->@Repository
Что не так или нет? deleteOne
подписи не являются двусмысленными относительно их параметров.
То же самое для производства.
Альфа
Здесь контроллеры:
@Controller
@RequestMapping(value="/personas")
public class PersonaDeleteOneController {
private final PersonaRestController personaRestController;
@Autowired
public PersonaDeleteOneController(PersonaRestController personaRestController){
this.personaRestController = personaRestController;
}
@GetMapping(value="/delete/{id}",
produces=MediaType.TEXT_HTML_VALUE)
public String deleteOne(@PathVariable String id, Model model){
model.addAttribute(personaRestController.findOneById(id));
model.addAttribute("root", "/personas/delete");
return "persona/deleteOne";
}
@DeleteMapping(value="/delete/{id}",
produces=MediaType.TEXT_HTML_VALUE)
public String deleteOne(@PathVariable String id, RedirectAttributes redirectAttributes){
personaRestController.deleteOne(id);
redirectAttributes.addFlashAttribute("message", "process.successful");
return "redirect:/message";
}
}
А также
@Controller
@RequestMapping(value="/personas")
public class PersonaRestController {
private final PersonaService personaService;
@Autowired
public PersonaRestController(PersonaService personaService){
this.personaService = personaService;
}
@DeleteMapping(value="/{id}")
public ResponseEntity<Void> deleteOne(@PathVariable String id){
personaService.deleteOne(id);
return ResponseEntity.noContent().build();
}
....
Как вы можете видеть, я не использую this.
выполнить вызовы метода.
1 ответ
Кажется, проблема в тебе pointcut
определение. Вы можете заметить, что ваш метод рекомендации выполняется только для методов с одним параметром, так как это связано с тем, что вы указали args(id)
в объявлении pointcut. Он должен работать так, как вы ожидаете, если вы удалите args(id)
, но в этом случае необходимо использовать какой-то обходной путь для раскрытия значения параметра.
Я думаю, что это странное поведение формы AspectJ, потому что такие конструкции, как execution(* *.*(String, ..)) && args(arg) && target(t))
имеет четкий смысловой смысл, чтобы охватить все методы с String
первый параметр и выставить его args
, Это может быть ошибка или особенность, по крайней мере, для разработчиков AspectJ.
Чтобы получить то, что вы хотите, вы можете использовать обходной путь с joinPoint.getArgs()
метод внутреннего совета, как это:
@Pointcut(value=
"execution(* com.manuel.jordan.controller.*.*Controller.deleteOne(..)) && target(object)")
public void deleteOnePointcut(Object object){}
@Before(value="ControllerPointcut.deleteOnePointcut(object)")
public void beforeAdviceDeleteOne(JoinPoint jp, Object object){
Object id = jp.getArgs()[0];
logger.info("beforeAdviceDeleteOne - @Controller: {} - Method: deleteOne - id: {}", object.getClass().getSimpleName(), id);
}