当ApplicationContext在另一个上下文中时,Spring @Autowired失败

时间:2015-10-22 04:48:03

标签: java spring autowired applicationcontext

我试图整合一个SDK,它通过它自己管理的上下文在内部使用Spring。无论Spring是否在要使用SDK的应用程序上使用,我都希望构建的jar可以使用。

我有一些在它自己运行时有效的东西。但是,如果我尝试在另一个Spring上下文中使用SDK(在我的情况下是一个基于Spring Boot的应用程序),我会得到一个org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type异常。

尽我所能,我无法理解如何使这个工作,或者实际上我做错了什么。下面的类显示了我正在做的事情,当org.example.test.MySDKTest成功通过时,org.example.testapp.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;
    }
}

package org.example.mysdk;

import org.springframework.beans.factory.annotation.Autowired;

public abstract class MyService {

    private MyServiceConfiguration configuration;

    @Autowired
    private MyAutowiredService myAutowiredService;

    MyService() {
    }

    MyService(MyServiceConfiguration configuration) {
        super();
        this.configuration = configuration;
    }

    public MyServiceConfiguration getConfiguration() {
        return configuration;
    }

    void setConfiguration(MyServiceConfiguration configuration) {
        this.configuration = configuration;
    }

    String getSomething(String in) {
        return "something + " + myAutowiredService.getThing(configuration.getValue()) + " and " + in;
    }
}

package org.example.mysdk;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope("prototype")
public class MyServiceImpl1 extends MyService {

    public MyServiceImpl1() {
    }

    public MyServiceImpl1(MyServiceConfiguration configuration) {
        super(configuration);
    }

    public String method1() {
        return this.getSomething("method1");
    }

}

package org.example.mysdk;

public class MyServiceConfiguration {

    private String value;

    public void setValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

package org.example.mysdk;

import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;

@Service
public class MyAutowiredService {

    private String thing = "a value";

    public String getThing(String in) {
        return thing + " " + in;
    }

    @PostConstruct
    void init() {
        System.out.println("MyAutowiredService bean created");
    }
}

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 {

}

测试

第一次测试失败,出现org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type异常,

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");

    }

}

如果我以完全错误的方式解决了这个问题,我很高兴听到有关如何以不同方式做到这一点的建议!

1 个答案:

答案 0 :(得分:0)

您必须修改两个文件。

首先App.java,它应扫描"org.example.mysdk"包以在抽象类myAutowiredService中注入MyService,如果不是,则必须在App.java中创建。并且MyServiceImpl 1 bean的名称必须与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中应该注入myServiceImpl中创建的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");
    }

}