代码反模式排查及Spring中ClassA与ClassB的@Autowired实现
原代码
抽象父类与子类
public abstract class ClassA { public String execute() { System.out.println("Do something..."); return processData(); } protected abstract String processData(); protected String callMethodFromAbstractClass(String somedata) { return somedata; } } public class ClassB extends ClassA { private String somedata; public ClassB (String somedata) { this.somedata= somedata; } @Override protected String processData() { return callMethodFromAbstractClass(somedata); } }
原调用方式
ClassA classA = new ClassB("somedata"); classA.execute();
问题1:父类方法调用子类实现的抽象方法,是否涉及反模式或存在问题?
这不仅不是反模式,反而属于模板方法模式的标准实现——父类定义固定的业务流程(比如execute()里的打印逻辑),把可变的业务逻辑(processData())交给子类实现,是日常开发中很常用的设计手法。
需要注意两个潜在坑:
- 绝对不要在父类的构造方法中调用
processData()这类抽象方法:子类实例化时会先执行父类构造,此时子类的成员变量还未初始化,调用子类实现会引发空指针或逻辑错误。 - 抽象方法的访问权限要合理:用
protected限定在子类可见,避免暴露不必要的接口。
你的代码里没有上述问题,写法是合规的。
问题2:如何将ClassA和ClassB作为Spring Bean,通过@Autowired实现注入?
因为ClassA是抽象类,无法直接实例化,所以只需把ClassB注册为Spring Bean,再通过@Autowired注入ClassA类型的实例即可,具体分两种场景:
场景1:构造参数是固定值或配置项
给ClassB添加@Component注解,同时用@Value注入构造参数(支持从配置文件读取):
@Component public class ClassB extends ClassA { private String somedata; // 用@Value注入构造参数,冒号后是默认值 public ClassB (@Value("${custom.somedata:default-value}") String somedata) { this.somedata= somedata; } @Override protected String processData() { return callMethodFromAbstractClass(somedata); } }
然后在需要使用的类中通过构造注入(Spring官方推荐方式)获取实例:
@Component public class BusinessService { private final ClassA classA; public BusinessService(ClassA classA) { this.classA = classA; } public void doBusiness() { classA.execute(); } }
场景2:构造参数需要动态生成或自定义
如果somedata是动态值,或者需要自定义ClassB的实例,可以用@Bean方法手动注册:
@Configuration public class BeanConfig { @Bean public ClassA classA() { // 这里可以自定义参数,比如从其他Bean获取或动态生成 return new ClassB("dynamic-somedata"); } }
同样在使用类中注入ClassA即可。
注意事项
如果有多个ClassA的实现类(比如ClassC也继承ClassA),需要用@Qualifier指定要注入的Bean:
public BusinessService(@Qualifier("classB") ClassA classA) { this.classA = classA; }
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

