Пользовательский фасольпроцессор ступенчатая яма помнить

Spring

задний план

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 должна быть независимой.