Я работаю с
- Spring Framework 4.3.3
- AspectJ 1.8.9
У меня есть два @Controllers
, один для mvc
, а другой для rest
. Каждый использует как зависимость @Service
.
У меня есть следующий метод отдыха
package com.manuel.jordan.controller.persona;
@Controller
@RequestMapping(value="/personas")
public class PersonaRestController {
@PutMapping(value="/{id}", consumes={MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<Void> updateOne(@PathVariable String id, @Validated @RequestBody Persona persona){
persona = personaService.updateOne(persona);
return ResponseEntity.noContent().build();
}
Обратите внимание на второй параметр, который я использую @Validated
У меня есть следующий Pointcut:
@Pointcut(value=
"execution(* com.manuel.jordan.controller.persona.PersonaRestController.updateOne(..))")
public void updateOnePointcut(){}
И следующий совет Around:
@Around(value="PersonaRestControllerPointcut.updateOnePointcut()")
@Transactional(noRollbackFor={Some exceptions})
public Object aroundAdviceUpdateOne(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
logger.info("Beginning aroundAdviceUpdateOne - Class: {}, Method: {}",
proceedingJoinPoint.getTarget().getClass().getSimpleName(),
proceedingJoinPoint.getSignature().getName());
....
}
Через Spring MVC Test
Когда я отправляю действительные данные:
Такие как:
resultActions = mockMvc.perform(put(uri).contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.header("Accept-Language", locale.toString())
.content(JsonTransformerSupport.objectToJson(personaValid))).andDo(print());
or by
RequestEntity<Persona> requestEntity = RequestEntity.put(uri).contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.header("Accept-Language", locale.toString())
.body(personaValid);
Посредством Gradle
отчетов я могу подтвердить, что совет @Around
работает так, как ожидалось. Он просто наблюдает Beginning aroundAdviceUpdateOne - Class ....
текст в отчете, а остальная часть совета работает так, как ожидается.
Проблема возникает, когда я отправляю недействительные данные для проверки через @Validated
Используя два способа, показанных выше, но просто изменив personaValid
на personaInvalid
(пустые поля, нарушение минимальных и максимальных границ и т. Д.), Я понял, что совет @Around
всегда игнорируется. Это подтверждает, что Beginning aroundAdviceUpdateOne - Class ....
никогда не появляется.
Примечание: даже если совет @Around
не работает, выполняется процесс проверки. То есть нет никаких исключений. Метод @Test
проходит.
Вот некоторые соображения.
- У меня такое же поведение с советом
@Before
. - Я предполагаю, что до выполнения метода
PersonaRestController.updateOne
@Around
(даже@Before
) совет должен сделать свою работу. Неважно, верны ли данные или нет. - У меня этот сценарий полностью действителен, когда я отправляю данные, действительные или недействительные, на не контроллер отдыха.
Этот метод:
@PutMapping(value="/update/{id}",
consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces=MediaType.TEXT_HTML_VALUE)
public String updateOne(@PathVariable String id,
@Validated @ModelAttribute Persona persona,
BindingResult result,
RedirectAttributes redirectAttributes){
Тот же @Around
совет работает, только со следующим вариантом (обратите внимание на ||
):
@Around(value="PersonaRestControllerPointcut.updateOnePointcut() || PersonaControllerPointcut.updateOnePointcut()")
@Transactional(noRollbackFor={some exceptions })
public Object aroundAdviceUpdateOne(JoinPoint proceedingJoinPoint) throws Throwable {
Обновление 01
Поэтому 4 сценария, в которых совет @Around
должен работать:
- метод без отдыха с действительными данными (работает)
- метод без отдыха с недопустимыми данными (работает)
- метод отдыха с достоверными данными (работает)
- метод rest с недопустимыми данными (сбой или игнорирование -
@Around
не выполняется)
Опять же: @Validated
работает так, как ожидается для методов отдыха и без отдыха. Проблема связана с советом @Around
, он не работает когда метод Rest
выполняется только тогда, когда отправляются недопустимые данные. Что не так? или пропал без вести?
Обновление 02
@Validated
is:
Вариант Valid JSR-303, поддерживающий спецификацию групп валидации. Разработан для удобного использования с поддержкой Spring JSR-303, но не для JSR-303.
Это из его API
Кажется, это не AOP
аннотация. Это просто аннотация Spring. Мой @Pointcut
не заботится об аннотациях и не проверяет их. Он использует updateOne(..)
Обновление 03
Даже добавив
@Aspect
@Component
@Transactional
@Order(0)
class PersonaRestControllerAspect {
Не работает так, как ожидается.
Обновление 04
у меня есть
@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
@Override
public Validator getValidator() {
return validatorConfig.localValidatorFactoryBean();
}
...
Откуда взялся Validator
:
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(){
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(rrbms);
return localValidatorFactoryBean;
}
Этот rrbms
экземпляр ReloadableResourceBundleMessageSource
, который загружает много .properties
файлов, один из них "classpath:/com/manuel/jordan/validation/validation"
.
@Validated
аннотаций? - person Sergey Bespalov   schedule 07.10.2016@Validated
работает так, как ожидалось. Проблема в совете@Around
. Большая часть конфигурации описана здесь: stackoverflow.com/a/39842293/3665178 - person Manuel Jordan   schedule 07.10.2016Update 01
. - person Manuel Jordan   schedule 07.10.2016Update 02
(перечитайте разделUpdate 01
, на всякий случай тоже) - person Manuel Jordan   schedule 07.10.2016@Order(0)
для моего@Aspect
, кажется, вы правы, потому что все суперклассы этогоMethodValidationPostProcessor
принадлежат их собственным пакетам, и все они содержат терминaop
. - person Manuel Jordan   schedule 07.10.2016Update 03
. Я не знаю, что делать .. - person Manuel Jordan   schedule 09.10.2016Update 04
. Спасибо - person Manuel Jordan   schedule 10.10.2016