Tomcat 啟動階段,自動識別所有繼承特定基類的 DAO 實現類,並向其注入公共依賴(如 DataSource、RedisTemplate 等)。
在容器實例化 Bean 前,掃描並修改 Bean 定義:
@Component
public class DaoInjector implements ApplicationContextAware, BeanFactoryPostProcessor {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
// 可選:獲取上下文
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
String className = bd.getBeanClassName();
if (className != null) {
try {
Class> clazz = Class.forName(className);
// 判斷是否為目標 DAO 實現類(如實現 BaseDao 接口或繼承 BaseDaoImpl)
if (BaseDao.class.isAssignableFrom(clazz) && !clazz.isInterface()) {
// 動態添加依賴注入屬性
MutablePropertyValues mpv = bd.getPropertyValues();
if (!mpv.contains("dataSource")) {
mpv.addPropertyValue(new PropertyValue("dataSource", new RuntimeBeanReference("dataSource")));
}
if (!mpv.contains("redisTemplate")) {
mpv.addPropertyValue(new PropertyValue("redisTemplate", new RuntimeBeanReference("redisTemplate")));
}
}
} catch (ClassNotFoundException ignored) {}
}
}
}
}
在 Bean 初始化後、注入完成前,通過反射強制設置字段:
@Component
public class DaoInjectionPostProcessor implements BeanPostProcessor, Ordered {
@Autowired private DataSource dataSource;
@Autowired private RedisTemplate redisTemplate;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
Class> clazz = bean.getClass();
// 掃描當前類及父類字段
while (clazz != null && clazz != Object.class) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getType() == DataSource.class && field.getAnnotation(Autowired.class) != null) {
field.setAccessible(true);
ReflectionUtils.setField(field, bean, dataSource);
} else if (field.getType() == RedisTemplate.class && field.getAnnotation(Autowired.class) != null) {
field.setAccessible(true);
ReflectionUtils.setField(field, bean, redisTemplate);
}
}
clazz = clazz.getSuperclass();
}
return bean;
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // 優先執行
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableDaoInjection {}
@Configuration
public class DaoInjectionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 掃描標註 @Repository 或特定包下的類,自動註冊 BeanPostProcessor
registry.registerBeanDefinition("daoInjectionProcessor",
BeanDefinitionBuilder.genericBeanDefinition(DaoInjectionPostProcessor.class).getBeanDefinition());
}
}
// 啟用類上添加 @EnableDaoInjection
BeanPostProcessor 方案二,非侵入式、順序可控。@ConditionalOnMissingBean 避免重複注入。Spring 提供豐富擴展點,合理選擇可實現靈活的自動化裝配,但務必權衡複雜度與可讀性。