由使用@Inject的第3方库实现的Spring Bean与Spring的注入机制冲突 [英] Spring Bean implemented by a 3rd party library that uses @Inject conflicting with Spring's injection mechanism
问题描述
我正在尝试通过第三方库(OWL API)中的类实现 @Bean
。
I am trying to have a @Bean
implemented by a class from a 3rd party library (OWL API).
此实现使用 @Inject
批注。 Spring试图解释它,从而干扰了第三方库的注入机制并避免其按预期工作。
This implementation uses an @Inject
annotation. Spring tries to interpret it, interfering with the injection mechanism of the 3rd party library and avoiding it to work as intended.
有没有一种方法可以指导Spring进行操作。实例化bean时,忽略bean实现的 @Inject
批注?
Is there a way to instruct Spring to ignore the @Inject
annotations of the bean implementation, when instantiating the bean?
我发现很少有关此主题的问题,但没有一个可以在我的上下文中提供可用的解决方案。
I found few questions about this subject but none of them provided a solution usable in my context.
我实际上通过将第三方对象包装在匿名类中来自己解决了此问题,显然为Spring设置了障碍,并阻止它查看此对象(请参阅下面的第3点),但我认为这是一个丑陋的解决方法。
I actually managed to resolve the issue myself, by wrapping the 3rd party object in an anonymous class, apparently creating a barrier for Spring and preventing it to look into this object (see the point 3. below), but I consider it to be an ugly workaround.
详细信息:
根据OWL API文档, OWLOntologyManager
的创建方式如下:
According to the OWL API documentation, the OWLOntologyManager
is to be created like this:
OWLOntologyManagerFactory ontologyManagerFactory = new OWLManager();
OWLOntologyManager owlOntologyManager = ontologyManagerFactory.get();
//... use owlOntologyManager
确实,在我运行的Spring应用程序中。但是,我需要具有 OWLOntologyManagerFactory
和 application
范围以及 OWLOntologyManager
具有 Session
范围。
Indeed, in my Spring application that was working. However, I need to have the OWLOntologyManagerFactory
with an application
scope and OWLOntologyManager
with a Session
scope.
所以我将这两个对象声明为Spring @Bean
,并具有适当的范围,并开始收到错误:
So I declared each of these two objects as a Spring @Bean
, with an appropriate scope and started to receive an error:
Error创建名称为 scopedTarget.sessionOWLOntologyManager的bean:通过方法 setIRIMappers参数0表示的不满足的依赖关系;嵌套的异常是org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为 java.util.Set的合格Bean:应该至少有1个有资格作为自动装配候选的Bean。依赖注释:{}
请参见下面的代码示例。
See below samples of the code.
- 功能性代码首次测试,不满足应用程序需求:
@RestController
public class OntologiesController {
@RequestMapping("ontologies")
public String manager_loadOntology(
@RequestParam(value="ontologyIriString") String ontologyIriString
) throws OWLOntologyCreationException
{
OWLOntologyManagerFactory ontologyManagerFactory = new OWLManager();
OWLOntologyManager owlOntologyManager = ontologyManagerFactory.get();
OWLOntology ontology = owlOntologyManager.loadOntology(IRI.create(ontologyIriString));
return ontology.toString();
}
}
- 非功能代码无法创建具有以上引用的错误的OWLOntologyManager。
@Configuration
public class ApplicationScopeConfig {
@Bean
@ApplicationScope
public OWLOntologyManagerFactory applicationOWLOntologyManagerFactory() {
return new OWLManager();
}
}
@Configuration
public class SessionScopeConfig {
@Autowired
OWLOntologyManagerFactory applicationOWLOntologyManagerFactory;
@Bean
@SessionScope
public OWLOntologyManager sessionOWLOntologyManager() {
return applicationOWLOntologyManagerFactory.get();
}
}
@RestController
public class OntologiesController {
@Autowired
private OWLOntologyManager sessionOWLOntologyManager;
@RequestMapping("ontologies")
public String manager_loadOntology(
@RequestParam(value="ontologyIriString") String ontologyIriString
) throws OWLOntologyCreationException
{
OWLOntology ontology = sessionOWLOntologyManager.loadOntology(IRI.create(ontologyIriString));
return ontology.toString();
}
}
- 功能代码可以根据需要工作,但很难看,有什么方法可以改进它吗?
在第二点中的代码中如下修改了sessionOWLOntologyManager(),将其包装到一个匿名类中,该类阻止Spring查看真正的owlOntologyManager。
In the code from the point 2 I modified the sessionOWLOntologyManager() as follows, wrapping it to an anonymous class that prevents Spring to look into the real owlOntologyManager.
@Bean
@SessionScope
public OWLOntologyManager sessionOWLOntologyManager() {
final OWLOntologyManager owlOntologyManager = applicationOWLOntologyManagerFactory.get();
return new OWLOntologyManager() {
public void clearOntologies() {
owlOntologyManager.clearOntologies();
}
//additional 400 lines implementing all methods by delegating to owlOntologyManager
//Apparently that creates a barrier for Spring so it does not conflict with the
//@Inject annotation in the implementation of the original owlOntologyManager,
//but in spite of having IDE support to generate this delegation, I consider it
//as an workaround.
}
}
推荐答案
As最终证明,这与配置Spring以忽略带注解的依赖项有关@Inject ,所以我认为获得更好答案的机会很低,我会在对自己的回复中发表自己的其他发现。
As it eventually turns out that this is related to Configuring Spring to ignore dependencies annotated with @Inject, so I assume that a chance to get better answers is low and I post my additional findings in a reply to myself.
-
负责识别@Inject的类是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor。根据我对Spring的了解,我无法拦截其行为。相关问题中提到的类SpringBeanAutowiringInterceptor在Spring 5中不存在。
The class responsible for recognizing the @Inject is org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor. With my Spring knowledge I was however not able to intercept its behavior. The class SpringBeanAutowiringInterceptor, mentioned in the related question, does not exist in Spring 5.
现在,我对第3点的解决方案进行了改进。我没有生成许多委托方法(可以由IDE自动完成),而是使用反射使用下面的代码。好处是,如果我有一天要升级OWLAPI库,它将更能抵抗更改。另外,它的行数明显更少。我认为反射的性能可能较低。
For now I go with an improvement to my solution in the point 3. Instead of generating dozens of delegating methods (it can be done automatically by IDE), I go with the code below, using the reflection. The advantage is that it will be more resistant to changes if I should upgrade the OWLAPI library one day. Also it has significantly less lines. I assume that the reflection might be less performant.
@Bean
@SessionScope
public OWLOntologyManager sessionOWLOntologyManager() {
final OWLOntologyManager owlOntologyManager = applicationOWLOntologyManagerFactory.get();
//Instead of returning owlOntologyManager directly,
//the delegating proxy prevents Spring to resolve @Inject annotations
//in the implementation of owlOntologyManager.
return (OWLOntologyManager)Proxy.newProxyInstance(
owlOntologyManager.getClass().getClassLoader(),
owlOntologyManager.getClass().getInterfaces(),
(o, method, args) ->
method.invoke(owlOntologyManager, args)
);
}
这篇关于由使用@Inject的第3方库实现的Spring Bean与Spring的注入机制冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!