如何在CorDapp项目中注入Spring对象?@Autowired注入为空求助
在CorDapp中整合Spring并实现依赖注入的解决方案
我之前在CorDapp项目里尝试过整合Spring框架,刚好碰到过和你一样的@Autowired注入失败的问题。核心原因是CorDapp默认的REST API由Corda自带的Jersey容器管理,而非Spring容器——你标记了@Component的ExampleApi其实是由Jersey手动实例化的,Spring根本没机会为它注入依赖。
下面是具体的解决步骤,结合你的代码来调整:
1. 手动初始化Spring上下文
Corda节点不会自动加载Spring上下文,我们需要借助CordaService在节点启动时触发Spring Boot的初始化:
@CordaService public class SpringBootInitializer extends SingletonSerializeAsToken { private final AppServiceHub serviceHub; private ConfigurableApplicationContext springContext; public SpringBootInitializer(AppServiceHub serviceHub) { super(serviceHub); this.serviceHub = serviceHub; } @PostConstruct public void initSpringContext() { if (springContext == null) { // 禁用Spring自带的Web服务器,避免和Corda内置Jetty端口冲突 SpringApplication app = new SpringApplication(JerseyConfig.class); app.setWebApplicationType(WebApplicationType.NONE); springContext = app.run(); // 将Spring上下文存入Corda服务中心,方便后续获取 serviceHub.registerAttachment(springContext); } } public ConfigurableApplicationContext getSpringContext() { return springContext; } }
2. 让Jersey与Spring容器整合
修改你的JerseyConfig,让Jersey使用Spring的Bean工厂来获取REST资源,而不是手动注册类:
@Configuration @Component public class JerseyConfig extends ResourceConfig { // 通过构造方法注入Spring上下文 public JerseyConfig(ApplicationContext context) { // 注册Spring组件提供者,让Jersey能从Spring上下文获取Bean register(SpringComponentProvider.class); // 扫描指定包下的REST资源和Spring组件 packages("com.example"); } @Bean public ServletRegistrationBean jerseyServlet(ApplicationContext context) { ServletContainer servletContainer = new ServletContainer(new JerseyConfig(context)); ServletRegistrationBean registration = new ServletRegistrationBean(servletContainer, "/rest/*"); registration.addInitParameter( ServletProperties.JAXRS_APPLICATION_CLASS, JerseyConfig.class.getName()); return registration; } }
3. 调整REST API的实例化方式
现在ExampleApi需要由Spring来管理,所以它的CordaRPCOps依赖也要通过Spring注入。先创建一个配置类来提供CordaRPCOps的Bean:
@Configuration public class CordaBeanConfig { @Autowired private SpringBootInitializer springInitializer; @Bean public CordaRPCOps cordaRPCOps() { // 从Corda的AppServiceHub获取RPC操作实例 return springInitializer.getServiceHub().getCordaRPCOps(); } }
然后修改ExampleApi的构造方法,让Spring注入CordaRPCOps:
@Path("example") @Component public class ExampleApi { private final CordaRPCOps rpcOps; private final CordaX500Name myLegalName; @Autowired TestComp testComp; // 新增@Autowired注解,让Spring注入CordaRPCOps @Autowired public ExampleApi(CordaRPCOps rpcOps) { this.rpcOps = rpcOps; this.myLegalName = rpcOps.nodeInfo().getLegalIdentities().get(0).getName(); } @GET @Path("metoo") @Produces(MediaType.APPLICATION_JSON) public String whoamitest() { return testComp.getMyName(); } }
4. 排查依赖冲突
Corda本身依赖部分Spring组件,确保你使用的Spring Boot版本(1.5.9.RELEASE)和你的Corda版本兼容(比如Corda 4.x系列适配Spring Boot 1.5.x)。如果出现依赖冲突,可以在build.gradle中排除重复的Spring模块:
compile (group: 'org.springframework.boot', name: 'spring-boot-starter-jersey', version: '1.5.9.RELEASE'){ exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' exclude group: 'org.springframework', module: 'spring-core' // 如果Corda已包含该模块 }
关键注意点
- 禁止Spring Boot启动独立Web服务器:必须设置
WebApplicationType.NONE,否则会和Corda的内置Jetty服务器抢占端口。 - 确保所有需要Spring管理的类都在扫描包范围内:
JerseyConfig的packages("com.example")要覆盖到ExampleApi、TestComp等类的所在包。
内容的提问来源于stack exchange,提问作者Jayant
相关产品推荐
相关产品推荐

