задний план
BeanPostProcessor — это один из механизмов расширения Spring, и его положение в жизненном цикле Bean выглядит следующим образом:
Как правило, мы можем использовать его для выполнения некоторой обработки до и после создания экземпляра компонента, например, для сбора и обработки пользовательских аннотаций для присвоения значений переменным-членам.
проблема
Теперь есть три класса: AnnotationProcessor используется для обработки пользовательских аннотаций, Anno — это настраиваемая аннотация, а MyProcessor полагается на AnnotationProcessor для обработки результатов.
@Component
public class AnnotationProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Anno.class) != null) {
//对字段做处理
}
}
return bean;
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno {
}
@Component
public class MyProcessor implements BeanPostProcessor {
@Anno
private String str;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//str此时为null
return null;
}
}
После запуска программы вы обнаружите, что строка str, полученная с помощью MyProcessor#postProcessAfterInitialization(), пуста Почему это так? Как мы можем сделать так, чтобы str уже обрабатывался AnnotationProcessor?
анализ проблемы
Как мы можем работать с Spring BeanPostProcessor, глядя на представление исходного кода. Поскольку мой процессорЭто также сам bean-компонент, тогда мы можем создать его экземпляр для SpringMyProcessor, чтобы увидеть, что в данный момент находится в соответствующей коллекции BeanPostProcessor.
Код достигает местоположения AbstractAutowireCapableBeanFactory#doCreateBean(), где выполняется обработка BeanPostProcessor:
Видно, что при создании экземпляра MyProcessor в наборе BeanPostProcessor, который был зарегистрирован в контейнере в это время, есть только некоторые встроенные BeanPostProcessors в Spring, и в это время нет собственного BeanPostProcessor.
Посмотрим, как регистрируется BeanPostProcessor, код приходит в PostProcessorRegistrationDelegate#registerBeanPostProcessors() (часть кода опущена)
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 1、注册实现了PriorityOrdered的BeanPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 2、注册实现了Ordered接口的BeanPostProcessor
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
//3、注册一般的BeanPostProcessor(即示例中的AnnotationProcessor、MyProcessor) List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
//这里会触发AnnotationBeanPostProcessor的实例化,但此时registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors)未执行,AnnotationBeanPostProcessor未注册到BeanFactory中,所以在示例中拿不到AnnotationBeanPostProcessor的处理结果
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
//4、注册Spring内部用的BeanPostProcessor
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
}
На этом этапе мы видим, что наш пользовательский BeanPostProcess обрабатывается на третьем шаге.В это время BeanPostProcess будет сначала создан, а затем зарегистрирован в контейнере, поэтому MyProcessor в нашем примере не будет обрабатываться AnnotationProcessor.
Так как это можно лечить? Мы можем увидеть третий шаг, прежде чем первый и второй шаги будут зарегистрированы, чтобы реализовать интерфейсы PriorityOrdered BeanPostProcessor или Ordered, если мы позволим AnnotationProcessor достичь одного из этих двух интерфейсов, которые могут достичь нашей цели.
в заключении
Из этого можно сделать вывод, что если вы хотите, чтобы атрибуты, используемые в MyProcessor, обрабатывались AnnotationProcessor, вам нужно заставить AnnotationProcessor реализовать интерфейс PriorityOrdered или Ordered.
Наконец
Какие точки оптимизации есть в Spring для обработки зависимостей BeanPostProcessor?
Личное понимание: BeanPostProcessor последней обработки может зависеть от результата обработки предыдущего BeanPostProcessor. Для BeanPostProcessor с приоритетом это может быть достигнуто по приоритету, для BeanPostProcessor без приоритета это зависит от порядка объявления.
эмм... Разумно ли так играть в BeanPostProcessor?
Spring Design BeanPostProcessor разум не может разрешить BeanPostProcessor зависит от результатов другого компостногопроцессора, логика каждого процесса BeanPostProcessor должна быть независимой.