【问题标题】:Spring beans dependencies cycle - conversionService to DAO to PropertiesFile to conversionServiceSpring beans依赖循环——conversionService到DAO到PropertiesFile到conversionService
【发布时间】:2020-08-06 07:56:17
【问题描述】:

我的 Spring Boot 应用程序有一个注册到 ConversionService 的转换器,它依赖于一个服务,而后者又依赖于一个 Dao。 Dao 依赖于 @ConfigurationProperties 注释对象,该对象作为名为 hardwareProperties 的构造函数参数注入,该参数依赖于 ConversionService。如何打破这个循环?

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  conversionService defined in class path resource [com/xxxx/services/AppConfiguration.class]
↑     ↓
|  activityMessageConverter (field private com.xxxx.services.cp.services.interfaces.SubscriptionService com.xxxx.services.cp.converters.ActivityMessageConverter.subscriptionService)
↑     ↓
|  subscriptionServiceImpl defined in file [D:\projectXXX\target\classes\com\xxxx\services\cp\services\SubscriptionServiceImpl.class]
↑     ↓
|  subscriptionDao defined in file [D:\projectXXX\target\classes\com\xxxx\services\cp\dao\SubscriptionDao.class]
↑     ↓
|  hardwareProperties
└─────┘

package com.xxxx.services;
import com.xxxx.services.cp.converters.ActivityMessageConverter;
public class AppConfiguration {

    @Bean
    public ConversionServiceFactoryBean conversionService(ActivityMessageConverter activityMessageConverter) {
        ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
        factoryBean.setConverters(Set.of(activityMessageConverter));
        factoryBean.afterPropertiesSet();
        return factoryBean;
    }
}

package com.xxxx.services.cp.converters;
import com.xxxx.services.cp.services.interfaces.SubscriptionService;
@Component
public class ActivityMessageConverter implements Converter<Message, Activity> { 

    @Autowired
    @Qualifier("subscriptionServiceImpl")
    private SubscriptionService subscriptionService;

    public SubscriptionService getSubscriptionService() {
        return subscriptionService;
    }

    public void setSubscriptionService(SubscriptionService subscriptionService) {
        this.subscriptionService = subscriptionService;
    }

    @Override
    public Activity convert(Message message) {
        // Implementation
    }
}


package com.xxxx.services.cp.services;
@Component
public class SubscriptionServiceImpl implements SubscriptionService {

    private SubscriptionService subscriptionDAO;

    public SubscriptionServiceImpl(@Qualifier(value = "subscriptionDao") SubscriptionService subscriptionDAO) {
        setSubscriptionDAO(subscriptionDAO);
    }

    public SubscriptionService getSubscriptionDAO() {
        return subscriptionDAO;
    }

    public void setSubscriptionDAO(SubscriptionService subscriptionDAO) {
        this.subscriptionDAO = subscriptionDAO;
    }
}

package com.xxxx.services.cp.dao;
import com.xxxx.services.cp.services.interfaces.SubscriptionService;
@Component
@Repository
public class SubscriptionDao implements SubscriptionService {

    private HardwareProperties hardwareProperties;

    public SubscriptionDao(HardwareProperties hardwareProperties) {
        this.hardwareProperties = hardwareProperties;       
    }
}

package com.xxxx.services.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:hardware.properties")
@ConfigurationProperties(prefix = "hardware.api")
public class HardwareProperties {
    private String host;
    private Integer port;
    private String username;
    private String password;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

// Usage of conversionService.
processMessages(context,
                filteredMessages.stream()
                        .map(message -> this.conversionService.convert(message, Activity.class))
                        .collect(Collectors.toList()));

【问题讨论】:

  • 如果不再使用,为什么还要在类 AppConfiguration 中的 bean 定义中传递 ActivityMessageConverter 之类的参数
  • @tino89 ConversionService 在别处使用。 processMessages(context, filteredMessages.stream() .map(message -> this.conversionService.convert(message, Activity.class)) .collect(Collectors.toList()));
  • @tino89 更正了我的代码。为错误道歉。

标签: java spring-boot dependency-injection dependencies cyclic-reference


【解决方案1】:

您尝试通过 snnipet 修改 AppConfiguration 的方法:

@Bean
public ConversionServiceFactoryBean conversionService() {
    ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
    factoryBean.setConverters(Set.of(activityMessageConverter));
    factoryBean.afterPropertiesSet();
    return factoryBean;
}

【讨论】:

  • 我已修改我的问题以反映您的评论。此外,您的 sn-p 缺少函数参数。
  • 另外,问题的症结在于循环bean依赖注入,而不是conversionService bean的初始化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 2019-02-22
  • 2016-08-02
  • 1970-01-01
相关资源
最近更新 更多