Spring boot SpringBoot-属性占位符配置无法与@Service annotation一起使用
我试图使用属性占位符值定义服务bean名称。但是出现错误,表示找不到特定名称的bean。我知道问题在于读取属性值,因为在硬编码值时,它正在工作。请帮助我,因为我需要从属性文件读取值。下面的代码片段: 应用程序属性Spring boot SpringBoot-属性占位符配置无法与@Service annotation一起使用,spring-boot,property-placeholder,Spring Boot,Property Placeholder,我试图使用属性占位符值定义服务bean名称。但是出现错误,表示找不到特定名称的bean。我知道问题在于读取属性值,因为在硬编码值时,它正在工作。请帮助我,因为我需要从属性文件读取值。下面的代码片段: 应用程序属性 event.testRequest=TEST_REQUEST 服务等级 @Service("${event.testRequest}") // This is not working, getting "No bean named 'TEST_REQUE
event.testRequest=TEST_REQUEST
服务等级
@Service("${event.testRequest}") // This is not working, getting "No bean named 'TEST_REQUEST' available" error
// @Service("TEST_REQUEST") // This is working
public class TestRequestExecutor extends DefaultExecutionService {
...
}
另外,为了确认属性值是否正确读取,我尝试使用@value(${event.testRequest}”)私有字符串值
,其中我得到了预期的值“TEST_REQUEST”。不知道如何将其与@Service annotation一起使用
编辑:
为了详细说明外部化服务bean名称的需要,我使用工厂模式来获取基于事件名称(事件名称,如Event1、Event2..)的实现。如果事件名称发生了更改,则更改将仅出现在属性文件上,而不是使用属性占位符的服务bean名称上
@RestController
public class RequestProcessController {
@Autowired
private ExecutorFactory executorFactory;
..
ExecutionService executionService = executorFactory.getExecutionService(request.getEventType());
executionService.executeRequest(request);
..
}
@Component
public class ExecutorFactory {
private BeanFactory beanFactory;
public ExecutionService getExecutionService(String eventType) {
return beanFactory.getBean(eventType, DefaultExecutionService.class);
}
这里的DefaultExecutionService
有如下不同的实现
@Service("${event.first}")
public class Event1Executor extends DefaultExecutionService {..}
..
@Service("${event.second}")
public class Event2Executor extends DefaultExecutionService {..}
event.first = Event1
event.second = Event2
所以基本上在将来,如果Event1名称更新为EventOne,我只需要更新属性文件,而不是服务类
非常感谢任何帮助!谢谢 有些东西你可以试试。尽管如此,我不建议这样做 尝试创建
BeanNameGenerator
并使用BeanNameGenerator(BeanNameGenerator BeanNameGenerator)
方法将其提供给SpringApplicationBuilder
。如果您感到好奇,这里是默认实现的一个示例
如果我理解正确,您有多个此服务的实现,您必须根据属性文件中提供的名称选择一个。如果是这样的话,请看一看。如果这些实现依赖于不同的配置文件,请查看
详细解释后编辑:
我认为实现这一点最简单的方法是注册您自己的bean。因此,请从您的执行者中删除@Service
注释。然后,使用DefaultListableBeanFactory
为执行者注册自己的BeanDefinition
代码如下所示:
@Value("${event.first}")
String event1;
DefaultListableBeanFactory context = .. //Get BeanFactory
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(Event1Executor.class);
gbd.getPropertyValues().addPropertyValue("someProperty", "someValue");
context.registerBeanDefinition(event1, gbd);
Event1Executor bean = (Event1Executor) context.getBean(event1);
您可能可以使用BeanFactoryAware
来获取bean工厂,如果您想在注册bean之前设置其他参数,则可以使用BeanDefinitionBuilder
。好的,现在它已清除
我认为您可以通过更改实现来实现这种行为:
@AllArgsConstructor // note, its not a component - I'll use @Configuration
public class ExecutorFactory {
private final Map<String, DefaultExecutionService> executorByEventName;
public DefaultExecutorService getExecutionService(String eventType) {
return executorByEventName.get(eventType);
}
不必与bean工厂一起工作,代码< > ExtutoRealStudio,而应考虑创建以下实现:
@AllArgsConstructor // note, its not a component - I'll use @Configuration
public class ExecutorFactory {
private final Map<String, DefaultExecutionService> executorByEventName;
public DefaultExecutorService getExecutionService(String eventType) {
return executorByEventName.get(eventType);
}
然后,您可以从Java配置类创建一个ExecutorFactory
,这就是为什么我没有在答案开头的ExecutorFactory
类上添加@Component
/@Service
注释的原因
@Configuration
public class MyConfiguration {
@Bean
public ExecutorFactory executorFactory(Map<String, DefaultExecutorService>
allServicesByQualifierName, MyConfigurationProperties config) {
Map<String, DefaultExecutorService> map = new HashMap<>();
allServicesByQualifierName.forEach((qualifierName, serviceBean) -> {
String actualEventName = config.getMappedEventName(qualifierName);
map.put(actualEventName, serviceBean);
});
return new ExecutorFactory(map);
}
}
然后访问应该支持获取所有事件的方法的配置。这可以通过不同的方式实现,最自然的方式可能是使用@ConfigurationProperties
注释并将application.yaml
的事件映射映射到Java中的映射。你可以阅读技术细节
作为旁注,虽然我使用了
@配置
方法,因为它看起来更清晰,但也可以在执行器工厂
上使用@服务
,但是我展示的类似逻辑将成为执行器工厂(构造函数或后期构造方法)的一部分,您仍然可以将bean名称映射注入实际bean,并将配置属性注入构造函数,这取决于您自己决定您不能在@Component
注释中使用占位符(@Service
就是其中之一)`。在我的书中,动态地分配一个名字也没有什么意义。你能详细说明一下为什么你真的需要这样做吗?spring需要引用springbean的名称,以获得正确的依赖项注入解析规则。我从来没有见过让它们充满活力的必要。我相信,如果你将这个问题表述出来,还有其他方法可以解决这个问题…@MarkBramnik我们有不同的实现方式。我们需要将其外部化以从属性文件中读取,因为每个占位符的名称(这些是事件名称)将来可能不同,并且它将在属性文件中更新。因此,我们可以使用现有代码,而不是进行代码更改,因为服务引用的是属性值。希望清楚。不是很清楚,所以您有不同的DefaultExecutionService实现,对吗?假设它可以工作,您在哪里使用已解析的bean名称,我的意思是,如果spring能够从配置文件解析@Service(“someService”)或@Service(“anotherService”),您在应用程序中在哪里使用字符串“someService”或“anotherService”?如果您只需要加载多个实现中的一个,您可以使用\@ConditionalOnProperty,在其他一些情况下,使用\@Profile可能会很方便(虽然在引擎盖下是一样的),但它的技术与您所要求的不同…@MarkBramnik请参阅我文章中的编辑部分。我已经详细解释过了。如果还不清楚,请告诉我。请看编辑部分,我已经详细解释了。谢谢你的详细说明。我会仔细检查你的方法,看看效果如何。
evt1 --> bean of type TestRequestExecutor1
evt2 --> bean of type TestRequestExecutor2