You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

代码反模式排查及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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 02:09:11