#java #spring #spring-boot
Вопрос:
Мне нужна помощь в написании моего собственного BeanPostProcessor. В моем контроллере я получаю @RequestParam String query
то, что мне нужно предварительно обработать перед дальнейшей обработкой запроса. Вот моя аннотация:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UTF8DecodeQuery {
}
Кроме того, я написал BPP для обработки этой аннотации во время выполнения:
@Component
public class UTF8DecodeQueryAnnotationBeanPostProcessor
implements IUTF8QueryDecryptor, BeanPostProcessor, Ordered {
private final ConcurrentHashMap<String, Class<?>>
bean2class = new ConcurrentHashMap<>();
public UTF8DecodeQueryAnnotationBeanPostProcessor() {
System.out.println("BPP constructor called");
}
@Override
public Object postProcessBeforeInitialization(Object
bean, String beanName) throws BeansException {
if(Arrays.stream(bean.getClass().getMethods())
.anyMatch(m -> m.isAnnotationPresent(UTF8DecodeQuery.class)))
bean2class.put(beanName, bean.getClass());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object
bean, String beanName) throws BeansException {
System.out.println("BPP after initialization called");
Class<?> aclass = bean2class.get(beanName);
if(aclass != null) {
return Enhancer.create(aclass, (MethodInterceptor) (obj, method, args, methodProxy) -> {
if(method.isAnnotationPresent(UTF8DecodeQuery.class)) {
//Some processing logic
//changing one of args
//Some processing logic
}
return methodProxy.invoke(bean, args);
});
}
return bean
}
}
Я аннотировал метод в @RestController
реализации.
Проблема в том, что метод postProcessBeforeInitialization
действительно вызывается (кстати, я вижу, что компонент моего контроллера rest присутствует в карте), но метод postProcessAfterInitialization
никогда не вызывается.
Пожалуйста, помогите мне!
P.S. Я не хочу использовать AOP и избегать использования BPP, это скорее образовательные цели, чем критическая необходимость
Комментарии:
1. Вы не хотите использовать AOP, но вы, более или менее, уже используете AOP, для создания и декодирования прокси-сервера. Также с этим лучше справляться в специализированной
HandlerMethodArgumentResolver
. При этом метод должен быть вызван, но действительно ли он не вызывается? Или контроллер не улучшен (что на самом деле немного опасно с аннотациями, которые там есть, это может привести к тому, что SpringMVC больше не сможет читать аннотации).2. @M. Deinum Спасибо вам за ваш комментарий. Да, метод не вызывается, точка останова и отсутствие
"BPP after initialization called"
в stdout свидетельствуют о том, что он не вызывается. Не могли бы вы объяснить свое последнее предложение? Извините, это был мой первый опыт работы с BPP.3. В BPP вы создаете прокси-сервер фактического класса. Поскольку (некоторые) аннотации не наследуются, это может создать проблему для их обнаружения Spring MVC. Но, как уже говорилось, тем не менее, он должен быть вызван, полностью ли запущен ваш контекст? Вы также реализуете несколько интерфейсов, хотя это не должно быть проблемой, это может быть.
4. Но Spring обнаруживает их, так как карта не пуста, она содержит ровно один компонент с методом, отмеченным моей аннотацией. Как я уже сказал,
postProcessBeforeInitialization
вызывается и работает правильно (проверено в режиме отладки). Мой контекст полностью запущен, приложение работает нормально, за исключением этой части