0

我有一个创建 bean 的 Spring Boot 基础抽象配置类。如果我从它继承,bean 将在我的控制器之后创建(它需要自动连接它,因此失败)。注意:它确实是在控制器之后创建的。所以它不能自动连接,但必须通过appContext.getBean( BeanType.class )

如果我改为覆盖子类中的 bean 方法,那么它会在控制器之前创建,并且可以自动连接。

我该如何解决这个问题并使超类 bean 定义与子类同时加载?

@SpringBootApplication
public class ChildConfig extends ParentConfig<PCTestBean>
{
    public ChildConfig()
    {
        super();
    }

    @Override
    public PCTestBean getT()
    {
        return new PCTestBean();
    }
}

public abstract class ParentConfig<T>
{
    public ParentConfig() {}

    @Bean
    public T createTestBean()
    {
        return getT();
    }

    public abstract T getT();
}

public class PCTestBean
{
}

@RestController
@RequestMapping( "/client" )
public class MyController
{
    @Autowired
    private PCTestBean pcTestBean;

    @RequestMapping( "/get" )
    @ResponseBody
    public String getClient(HttpServletRequest request) throws Exception
    {
        return pcTestBean.toString();
    }
}

@RunWith( SpringJUnit4ClassRunner.class )
@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@ContextConfiguration(
    classes = {
        ChildConfig.class
    }
)
public class TestConfigs
{
    @LocalServerPort
    private String port;

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Before
    public void setUp() throws Exception
    {
        mockMvc = MockMvcBuilders
            .webAppContextSetup( context )
            .build();
    }

    @Test
    public void testValidCall() throws Exception
    {
        MvcResult result = mockMvc.perform(
            MockMvcRequestBuilders.get( new URI( "http://localhost:" + port + "/client/get" ) )
        )
            .andExpect( MockMvcResultMatchers.status().isOk() ).andReturn();

        System.out.println( result.getResponse().getContentAsString() );
    }
}
4

2 回答 2

1

当 Spring 扫描你的配置类时ChildConfig,它会发现这个继承的方法

@Bean
public T createTestBean() {
    return getT();
}

并为其注册一个 bean 定义。该 bean 定义包含有关 bean 类型的元数据。该类型是从方法的返回类型推断出来的。在这种情况下,它被解析为Object因为类型变量T在其声明中没有边界,并且因为 Spring 不会尝试根据ChildConfig'extends ParentConfig<PCTestBean>子句中提供的类型参数来解析它。

当 Spring 然后尝试处理

@Autowired
private PCTestBean pcTestBean;

注入目标,它会寻找一个PCTestBean它认为没有的bean,因为缺少元数据。如果bean 没有通过其他强制命令初始化,那么 Spring 没有其他信息可以继续并认为 bean 不存在。

当您将代码更改为

而是覆盖子类中的bean方法

该方法的返回类型是PCTestBeanSpring 然后可以匹配@Autowired注入需求,找到(并初始化)bean,然后注入它。

到你使用的时候ApplicationContext#getBean(Class)PCTestBean已经初始化了。因此,Spring 可以依赖于实例的实际类型。它会或多或少地循环遍历所有 bean 并检查是否beanClass.isInstance(eachBean),返回匹配的那个(或者如果不止一个,则失败)。

Pankaj在他们的回答中建议使用@DependsOn(在您编辑问题之前,他们建议使用它是错误的)。这可以帮助建立我之前提到的顺序。


我不知道你的配置类有多广泛,你认为你需要泛型来抽象一些行为,但我建议你只删除泛型行为并在每个类中明确。

于 2018-01-31T05:17:00.593 回答
0

试试DependsOn注解,它保证子bean应该在父bean之后创建

@Configuration
public class ChildConfig extends ParentConfig
{
    public ChildConfig()
    {
        super();
    }


    @DependsOn("parentConfig")
    @Override
    public TestBean createTestBean()
    {
        return super.createTestBean();
    }*/
}

public abstract class ParentConfig
{
    public ParentConfig() {}

    @Bean (name ="parentConfig")
    public TestBean createTestBean()
    {
        return new TestBean();
    }
}
于 2018-01-31T00:39:09.803 回答