PAYATHON 2026

Spring 创建 pgService 失败:Specified class is an interface

支付老李

结论

pgService 的 Bean 配置将接口 com.majesco.dcf.pg.service.PGService 当成了可实例化的类。接口无法通过构造方法创建对象,因此 Spring 抛出了以下异常:

Specified class is an interface

将 Bean 的 class 改为 PGService 的具体实现类,例如 PGServiceImpl。也可以通过组件扫描注册实现类。注入时仍可使用 PGService 接口类型。

错误原因

配置中可能有类似的定义:

<bean id="pgService"
      class="com.majesco.dcf.pg.service.PGService"/>

Spring 处理普通 <bean> 时,会尝试调用 class 所指定类型的构造方法。PGService 是接口,没有构造方法,也不能直接实例化,所以应用上下文初始化失败。

问题通常不在导入 pg-context.xml 这一步。异常说明 Spring 已经读取了该文件,但在创建其中名为 pgService 的 Bean 时失败了。

方式一:在 XML 中配置实现类

假设接口和实现类如下:

package com.majesco.dcf.pg.service;

public interface PGService {
    void processPayment();
}
package com.majesco.dcf.pg.service.impl;

import com.majesco.dcf.pg.service.PGService;

public class PGServiceImpl implements PGService {

    @Override
    public void processPayment() {
        // Payment gateway integration
    }
}

pg-context.xml 中应填写具体实现类:

<bean id="pgService"
      class="com.majesco.dcf.pg.service.impl.PGServiceImpl"/>

如果实现类还依赖其他 Bean,可以使用属性注入:

<bean id="pgService"
      class="com.majesco.dcf.pg.service.impl.PGServiceImpl">
    <property name="paymentGatewayClient" ref="paymentGatewayClient"/>
</bean>

对应的实现类需要提供 setter:

public class PGServiceImpl implements PGService {

    private PaymentGatewayClient paymentGatewayClient;

    public void setPaymentGatewayClient(
            PaymentGatewayClient paymentGatewayClient) {
        this.paymentGatewayClient = paymentGatewayClient;
    }
}

构造器注入更合适:

<bean id="pgService"
      class="com.majesco.dcf.pg.service.impl.PGServiceImpl">
    <constructor-arg ref="paymentGatewayClient"/>
</bean>
public class PGServiceImpl implements PGService {

    private final PaymentGatewayClient paymentGatewayClient;

    public PGServiceImpl(PaymentGatewayClient paymentGatewayClient) {
        this.paymentGatewayClient = paymentGatewayClient;
    }
}

方式二:使用注解和组件扫描

也可以让 Spring 自动发现实现类:

package com.majesco.dcf.pg.service.impl;

import com.majesco.dcf.pg.service.PGService;
import org.springframework.stereotype.Service;

@Service("pgService")
public class PGServiceImpl implements PGService {

    @Override
    public void processPayment() {
        // Payment gateway integration
    }
}

然后在 XML 中启用组件扫描:

<context:component-scan base-package="com.majesco.dcf.pg"/>

启用组件扫描后,应删除重复的 XML Bean 定义,尤其不能继续保留以下配置:

<bean id="pgService"
      class="com.majesco.dcf.pg.service.PGService"/>

业务代码仍可面向接口注入:

@Autowired
private PGService pgService;

也可以使用构造器注入:

@Controller
public class PaymentController {

    private final PGService pgService;

    @Autowired
    public PaymentController(PGService pgService) {
        this.pgService = pgService;
    }
}

存在多个实现类时

如果 PGService 有多个实现,例如:

@Service("bankPgService")
public class BankPGServiceImpl implements PGService {
}
@Service("walletPgService")
public class WalletPGServiceImpl implements PGService {
}

只按接口类型注入会产生歧义。可以使用 @Qualifier 指定实现:

@Autowired
@Qualifier("bankPgService")
private PGService pgService;

也可以在首选实现类上添加 @Primary:

@Service
@Primary
public class BankPGServiceImpl implements PGService {
}

使用 XML 配置时,通过明确的 Bean ID 引用所需实现:

<bean id="bankPgService"
      class="com.majesco.dcf.pg.service.impl.BankPGServiceImpl"/>

<bean id="paymentController"
      class="com.majesco.dcf.pg.web.PaymentController">
    <constructor-arg ref="bankPgService"/>
</bean>

需要检查的配置

检查 pg-context.xml 及其导入的其他配置文件,搜索以下内容:

class="com.majesco.dcf.pg.service.PGService"

如果找到,应将其替换为实际实现类的完整限定名:

class="com.majesco.dcf.pg.service.impl.PGServiceImpl"

还需要确认:

  • PGServiceImpl 确实声明了 implements PGService。
  • 实现类不是 abstract。
  • 实现类位于运行时 classpath 中。
  • Spring 能访问该实现类的构造方法。
  • 构造器参数或属性所依赖的 Bean 均已配置。
  • 没有同时通过 XML 和 @Service 注册同名 Bean。
  • 如果需要通过接口创建 JDK 动态代理、MyBatis Mapper 或远程服务代理,应使用对应的 FactoryBean、扫描器或框架配置,不能将接口名直接写进普通的 <bean class="接口名">。

该异常发生在实例化阶段,与 Hibernate 的 dialect、default_schema、hbm2ddl.auto 等属性没有直接关系。先让 pgService 指向可实例化的实现类,Spring 才能继续创建其他 Bean。

备注:内容仅供参考。