Dependency injection with Spring (JSR 330 annotati

2020-04-16 18:50发布

问题:

I have an enterprise application built with Java 6, Spring Framework 3.1.2 and Mule-ESB 3.3.0, among other libraries not related to this question.

Our beans and services are all declared with @Named and @Inject JSR-330 annotations, respectively for automatic component scanning and for dependency injection (no EJBs, only service beans). When deployed into JBoss 4.2.3 (our test environment) everything works fine. However, when deployed into WebSphere 7, the JSR-330 annotations seem not to be working. The beans marked with @Named are just not detected, at all.

I can assure everything is configured right (since it is working in JBoss). Specifically, the <context:component-scan /> has the base-package attribute correctly defined and the scope-resolver attribute correctly configured to use Jsr330ScopeMetadataResolver (we tried without it too).

I am aware WebSphere 7 (7.0.0.23) may not support such kind of annotations. I am yet to test it with @Component and @Autowired Spring equivalents. Unfortunately, we would very much like to use JSR 330 annotations so our classes wouldn't directly depend on Spring, even though we're using Spring Framework under the hood.

Nevertheless, although I'd spent one full work's day looking for a definite statement that WebSphere 7 does not support JSR 330 annotations, I haven't found anything so far.

Further, I can't see why it would not work, since I'm assuming Spring Framework is the one doing all the work, through the <context:component-scan /> directive in the application-context.xml file.

Can anyone bring some light into this issue?

Is there a way to activate dependency injection via annotations in WebSphere 7?

If I switch back from the JSR 330 @Named / @Inject annotations to Spring's own @Component and @Autowired is it likely to work?

In a desperate attempt, can I extend Spring's ComponentScanBeanDefinitionParser so it will detect JSR 330 annotations even in WebSphere 7?

If nothing works, I will eventually fall back to plain XML configuration. That is highly undesirable, however, because there will be hundreds of beans to be manually configured in the XML.

回答1:

WebSphere 8 seems to be the correct version to use; it supports EE6 (WebSphere 7 is EE5), which in turn contains CDI 1.0 (hence JSR 299).

Below is a snippet from DeveloperWorks that summarises relationship between WebSphere versions, JSR 299 and JSR 300

Dependency injection is a technology that has surfaced in various implementations many times before making it into the Java EE world. The Spring Framework and the Google Guice library are popular implementations. In JSR 330, an attempt was made to include these capabilities into the J2SE platform. JSR 299 is a specification that used the APIs defined in JSR 330 and added more capabilities to support Java EE needs. IBM WebSphere Application Server V8 and V8.5 (non-Liberty profiles) are fully compliant Java EE 6 containers and implement JSR 299.



回答2:

I eventually came up with a workaround by extending both Component Scan and Autowire features of Spring Framework.

First, I added an inclusion filter to the Component Scanner so that @Named annotations were also considered eligible for detection and registration to the Spring Container:

<context:component-scan base-package="com.mycompany.mysystem">
    <context:include-filter type="annotation" expression="javax.inject.Named" />
</context:component-scan>

Following that, I also added a bean definition to org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcesso‌​r, extending the autowiring eligibility to @Inject annotations:

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
    <property name="autowiredAnnotationType" value="javax.inject.Inject" />
</bean>

Initially, this worked fine as to "reactivating" the @Named and @Inject annotations. However, I still had some problems of conflicting beans on the autowire candidates resolution process. This was due to the differences in the default resolution process of Spring and of JSR-330. This was no big issue, since only a few beans fell into that scenario. They were all solved by adding some strategically placed @Qualifier annotations.

Now everything is working fine and elegantly, with few extra configurations. Nevertheless, I still don't understand why this happened. All I know is that the following 3 lines do appear when I deploy the application into JBoss 4.2.3. On the other hand, they don't appear in WebSphere:

INFO  [org.springframework.context.annotation.ClassPathBeanDefinitionScanner] JSR-330 'javax.inject.Named' annotation found and supported for component scanning

and

DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Creating instance of bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
INFO  [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor] JSR-330 'javax.inject.Inject' annotation found and supported for autowiring

I still have no clue as to why this happens, since, as @Dreamer said, this should be a Spring's responsibility, and thus, out of WebSphere business.

If someone do have such a clue, please enlighten us. Im sure it would be wonderfully clarifying to everyone participating in this discussion.



回答3:

Agree with duffymo, it should work on WS 7. As Spring is on top of Websphere so Spring annotation is out of webshere's business(sort of).

One thing you probably need to check on WS 7(even though you said every configuration is correct as it works on JBoss) is click your application -> click Class loading and update detection, make sure the Classes loaded with local class loader first (parent last) is checked. That would make the server to take your application's library come first followed by websphere's library.