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。
备注:内容仅供参考。
