Java 当ApplicationContext位于另一个上下文中时,Spring@Autowired失败
我正试图整合一个SDK,它通过Spring自己管理的上下文在内部使用Spring。我希望构建的jar是可用的,无论Spring是否在想要使用SDK的应用程序上使用 当它自己运行时,我有一些东西可以工作。但是,如果我尝试在另一个Spring上下文(在我的例子中是基于Spring引导的应用程序)中使用SDK,我会得到一个Java 当ApplicationContext位于另一个上下文中时,Spring@Autowired失败,java,spring,autowired,applicationcontext,Java,Spring,Autowired,Applicationcontext,我正试图整合一个SDK,它通过Spring自己管理的上下文在内部使用Spring。我希望构建的jar是可用的,无论Spring是否在想要使用SDK的应用程序上使用 当它自己运行时,我有一些东西可以工作。但是,如果我尝试在另一个Spring上下文(在我的例子中是基于Spring引导的应用程序)中使用SDK,我会得到一个org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为的合格bean异常 尽管我尽了最大的努力,但
org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为的合格bean异常
尽管我尽了最大的努力,但我无法理解如何让它工作,或者我到底做错了什么。下面的类显示了我正在做的事情,org.example.testapp.MySDKTest失败并出现异常,而org.example.test.MySDKTest成功通过。抱歉,代码太多了,但我无法用简化的案例重现这个问题
SDK源代码
package org.example.mysdk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.example.mysdk.MyService;
import org.example.mysdk.MyServiceConfiguration;
public final class MySDK {
private static ApplicationContext applicationContext;
public static <T extends MyService> T getService(Class<? extends MyService> clazz, MyServiceConfiguration configuration) {
T tmp = (T) getApplicationContext().getBean(clazz);
tmp.setConfiguration(configuration);
return tmp;
}
private static ApplicationContext getApplicationContext() {
if (applicationContext == null) {
applicationContext = new AnnotationConfigApplicationContext(SpringContext.class);
}
return applicationContext;
}
}
测试
第一次测试失败,出现org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为的合格bean异常
package org.example.testapp;
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
@Autowired
MyServiceImpl1 service;
@Test
public void test() {
MyServiceConfiguration conf = service.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}
而且这个试验成功了,
package org.example.test;
import static org.junit.Assert.*;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
public class MySDKTest {
@Test
public void test() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
MyServiceImpl1 service = MySDK.getService(MyServiceImpl1.class, configuration);
assertEquals(service.getConfiguration().getValue(), "this is the instance configuration");
}
}
如果我用了完全错误的方法,我很高兴听到关于如何用不同的方式来做这件事的建议 您必须修改两个文件
首先App.java
,它应该扫描“org.example.mysdk”
包,在抽象类MyService
中注入myAutowiredService
,否则必须在App.java
中创建。而且MyServiceImpl
1bean的名称必须与myServiceImpl1
不同,因为它会发生冲突
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
@Configuration
@ComponentScan(basePackages = {
"org.example.testapp", "org.example.mysdk"
})
public class App {
@Bean
public MyServiceImpl1 myServiceImpl() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
其次,在MySDKTest.java
中,应该插入myservicecimpl
中创建的App.java
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
@Autowired
MyServiceImpl1 myServiceImpl;
@Test
public void createOxiAccountService() {
MyServiceConfiguration conf = myServiceImpl.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}
感谢@shazin的回答,我希望有两个完全独立的Spring上下文(基本上我不希望SDK用户知道/关心库在内部使用Spring)。有没有办法在两种情况下保持关注点的分离?
package org.example.mysdk;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {
"org.example.mysdk"
})
public class SpringContext {
}
package org.example.testapp;
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
@Autowired
MyServiceImpl1 service;
@Test
public void test() {
MyServiceConfiguration conf = service.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
@Configuration
@ComponentScan(basePackages = {
"org.example.testapp"
})
public class App {
@Bean
public MyServiceImpl1 myServiceImpl1() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
package org.example.test;
import static org.junit.Assert.*;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
public class MySDKTest {
@Test
public void test() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
MyServiceImpl1 service = MySDK.getService(MyServiceImpl1.class, configuration);
assertEquals(service.getConfiguration().getValue(), "this is the instance configuration");
}
}
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
@Configuration
@ComponentScan(basePackages = {
"org.example.testapp", "org.example.mysdk"
})
public class App {
@Bean
public MyServiceImpl1 myServiceImpl() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
@Autowired
MyServiceImpl1 myServiceImpl;
@Test
public void createOxiAccountService() {
MyServiceConfiguration conf = myServiceImpl.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}