За каждым явлением стоит причина.Чем причудливее ошибка, тем незаметнее детали.За каждой ошибкой стоит принцип и механизм работы фреймворка или кода.Чтобы устранить ошибку, нужно не только искать в сети , но также необходимо понять и обобщить лежащие в его основе принципы.
Мой коллега недавно изучает и использует Mybatis.Он использует MapperScannerConfigurer Mybatis для связанной конфигурации и надеется указать атрибуты, такие как basePackage и mappers, через конфигурацию yml. Для этого написан собственный класс конфигурацииStarterAutoConfiguration
и пользовательский класс атрибутовTkProperties
, а при инициализацииMapperScannerConfigurer
использовать, когдаTkProperties
свойства в . Однако это имеет неприятные последствия при инициализацииMapperScannerConfigurer
час,TkProperties
Атрибуты экземпляра живут и умирают в неинициализированном состоянии.
С этой целью мы потратили много времени на изучение причины, и, наконец, нам пришлось спросить другого крупного парня, только чтобы обнаружить, что за этой странной проблемой стоит такая-то причина.
Давайте сначала посмотрим на большого парня оMapperScannerConfigurer
реализация пользовательской конфигурации. Сначала он определяет пользовательский класс конфигурацииBkStarterAutoConfiguration
,использовать@EnableConfigurationProperties
Аннотации будутTkProperties
Объявлен как класс свойств конфигурации.
@Configuration
@EnableConfigurationProperties({TkProperties.class})
@AutoConfigureBefore(MybatisAutoConfiguration.class)
public class BkStarterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@Order(Ordered.HIGHEST_PRECEDENCE)
public TkProperties tkProperties() {
return new TkProperties();
}
}
НижеTkProperties
определение, используя@ConfigurationProperties
Аннотация объявляет префикс конфигурации атрибута, и два имени атрибутаbasePackage
а такжеmappers
.
@Data
@ConfigurationProperties(prefix = "tk")
public class TkProperties {
private String basePackage;
private String mappers;
}
MapperConfig
объявляется и настраиваетсяMapperScannerConfigurer
Класс конфигурации экземпляра, используя@Bean
АннотированныйmapperScannerConfigurer
метод для инициализации, параметры метода которогоTkProperties
.
@Configuration
public class MapperConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(TkProperties tkProperties) {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
//使用TkProperties的成员变量来配置mapperScannerConfigurer
mapperScannerConfigurer.setBasePackage(tkProperties.getBasePackage());
Properties properties = new Properties();
properties.setProperty("mappers", tkProperties.getMappers());
mapperScannerConfigurer.setProperties(properties);
return mapperScannerConfigurer;
}
}
Файл конфигурации yml показан ниже.
---
tk:
basePackage: cn.remcarpediem.mybatis.dao
mappers: cn.remcarpediem.mappers.BaseDao
На первый взгляд кажется, что в коде нет проблем, но во время выполнения, когда инициализируется экземпляр MapperScannerConfigurer, свойства экземпляра TkProperties не инициализируются успешно.
Должно быть много хорошо информированных читателей, которые уже знают причины этого явления. "Убийца" этоMapperScannerConfigurer
Реализованный интерфейсBeanDefinitionRegistryPostProcessor
. Нам все еще нужно медленно объяснять конкретные причины, потому что это включает в себя многие принципы Spring Boot.
первый,BeanDefinitionRegistryPostProcessor
интерфейс наследуетBeanFactoryPostProcessor
Интерфейс, все в целом правыBeanFactoryPostProcessor
Более знакомо, что это постпроцессор (PostProcessor) фабрики экземпляров (BeanFactory), и он похож на постпроцессор экземпляра (BeanPostProcessor).BeanFactoryPostProcessor
В файле определен только один метод.ApplicationContext
ВнутреннийBeanFactory
загруженBeanDefinition
после, но до создания экземпляра bean-компонента. Поэтому обычно мы можем реализовать этот интерфейс для создания экземпляра предыдущегоBeanDefinition
модифицировать. НапримерPropertySourcesPlaceholderConfigurer
просто поймиBeanFactoryPostProcessor
интерфейс, который используется для обработки@Value
Аннотируйте измененную переменную и измените ее значение.
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
иBeanDefinitionRegistryPostProcessor
Интерфейс простирается отBeanFactoryPostProcessor
,этоBeanDefinitionRegistry
постпроцессор, это может бытьBeanFactoryPostProcessor
Зарегистрируйте некоторые специальные до обнаруженияBeanDefinition
, например, можно зарегистрировать для определенияBeanFactoryPostProcessor
изBeanDefintion
, как мы упоминали ранееMapperScannerConfigurer
а такжеConfigurationClassPostProcessor
.
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
MapperScannerConfigurer
изpostProcessBeanDefinitionRegistry
в основном используетсяClassPathMapperScanner
сканироватьMybatis
изMapper
.ClassPathMapperScanner
наследоватьClassPathBeanDefinitionScanner
,существуетdoScan
полученный методомbasePackage
Все по указанному пути пакетаMapper
изBeanDefinition
, а затем зарегистрируйтесь.
иBeanPostProcessor
Это постпроцессор экземпляра Bean. Перед инициализацией каждого экземпляра компонента егоpostProcessBeforeInitialization
метод и вызвать его после инициализацииpostProcessAfterInitialization
метод.ConfigurationPropertiesBindingPostProcessor
ДостигнутоBeanPostProcessor
интерфейс для работы с@ConfigurationProperties
Модифицированный экземпляр.
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
Мы можем подвести итогBeanDefinitionRegistryPostProcessor
,BeanFactoryPostProcessor
а такжеBeanPostProcessor
Порядок и время действий трех постпроцессоров.
Отсюда мы также можем понять, почемуMapperScannerConfigurer
При инициализацииTkProperties
не был инициализирован, потому чтоConfigurationPropertiesBindingPostProcessor
не был инициализирован и неTkProperties
обрабатывать.
Если вы столкнулись с проблемами и ошибками, не просто нажмите на Baidu, чтобы решить проблему, а глубоко поймите механизм и принцип, лежащий в ее основе.Я надеюсь, что каждый сможет изучить более глубокие принципы и получить больше знаний.