文章目录
工作中难免会遇到这种情况,多个业务用到了相似的一套流程,只有一些细节不太一样,每次重复编写一整套流程感觉比较 Low,就想着写一个抽象类出来,提供一个通用模板方法把主要业务流程封装起来,提供空方法让子类有选择地覆盖不同的细节
抽象类中要封装某个业务,一般会使用到 RedisTemplate 等 Bean,而抽象类却并不能像普通类一样被 Spring 作为 Bean 创建并管理着,那么如何为抽象类中的属性赋值呢?如果让子类额外做 super.redis = redis 或类似的操作为父类赋值,使用麻烦还不够优雅,那 Spring 有办法解决这种问题吗?
当然有,只要抽象父类的字段添加 @Autowired 注解就可以了
举例如下
/**
* 抽象通用返利模板
*/
@Slf4j
public abstract class AbstractGenericRebateTemplate {
@Autowired
private Redis redis;
@Autowired
private RedissonClient redisson;
@Autowired
private MarketIntegration marketIntegration;
@Autowired
private GenericRebateRequestManager manager;
protected Object rebate(GenericRebateRequestDO request) {
...
}
...
}
@Slf4j
@Component
public class DemoRebateBiz extends AbstractGenericRebateTemplate {
public Object doBusiness() {
GenericRebateRequestDO record = new GenericRebateRequestDO();
record.setRequestNo(IdKit.getSerialNo()).setBusiness("business").setScene("scene");
return rebate(record);
}
}
原理
spring 解析 BeanDefinition 时并没有处理字段相关的内容, 而是在 getBean 时, 填充属性的 populateBean 过程中通过 AutowiredAnnotationBeanPostProcessor 的 postProcessProperties 方法, 拿到 bean 的 @Autowired 字段依赖 bean 并注入到该 bean 的对应字段内
postProcessProperties 方法中的 findAutowiringMetadata 方法, 用于查找 bean 中的 @Autowired 字段, 该方法会同时拿到该类及其父类中所有 @Autowired 字段, 并在接下来的 metadata.inject(bean, beanName, pvs) 中完成注入