Tested with the following tool chain:
Other requirements:
The full example is attached to this tutorial so looking around there should be easy.
<dependencies>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ejb_3.0_spec</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-interceptor_3.0_spec</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
[...]
</dependencies>
<build>
[...]
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
<finalName>spring-ejb</finalName>
</build>
Invoking mvn assembly:assembly on the project now will result in the .jar file target/spring-ejb-with-dependencies.jar being created which, opposed to target/spring-ejb.jar (the artifact created and installed to your local repository running mvn install), does contain all the content provided by any of the dependencies of the project. This file, by then, easily could be deployed to an application server like Glassfish.
In order to solve this we finally got SLF4J integrated into our applications which does exactly what we need here, adding the following entries to pom.xml:
[...]
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl104-over-slf4j</artifactId>
<version>1.5.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.5.0</version>
<scope>compile</scope>
</dependency>
[...]
Only thing left to mention here is to, in pom.xml, make sure the "real" implementations of commons-logging and log4j are exclused in case any packages (like Spring) depend upon them:
[...]
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.5</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
[...]
[...]
@Stateless
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class FooBean implements FooLocal {
@Autowired
private SampleBean sampleBean;
[...]
The Spring documentation on these issues surely could be more verbose names a few things how to extend and customize this mechanism, however in the most "common" use case, to make use of this approach a beanRefContext.xml file needs to be defined containing a definition of an implementation of the Spring BeanFactory interface, like, for example, the ClassPathXmlApplicationContext:
[...]
<bean id="factoryKey" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="application.xml"/>
</bean>
[...]
Configured this way, the beans to be exposed via Spring (and subsequently used within EJB classes) go to the application.xml context configuration:
[...]
<bean id="sampleBean" class="de.planconnect.ejb.test.samples.SampleBean"/>
[...]
Both files need to be found on the application classpath at runtime, putting them right into main/resources/ in the maven2 project structure has proven to work rather well.
[...]
<profiles>
<profile>
<id>production</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>deploy</phase>
</execution>
</executions>
<configuration>
<executable>/opt/appsrv/glassfish-v2/bin/asadmin</executable>
<arguments>
<argument>deploy</argument>
<argument>--precompilejsp</argument>
<argument>--user=admin</argument>
<argument>--passwordfile=${user.home}/.asadminpass</argument>
<argument>--host=appserver</argument>
<argument>--port=4848</argument>
<argument>target/spring-ejb-jar-with-dependencies.jar</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>testing</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>deploy</phase>
</execution>
</executions>
<configuration>
<executable>/opt/appsrv/glassfish-v2/bin/asadmin</executable>
<arguments>
<argument>deploy</argument>
<argument>--precompilejsp</argument>
<argument>--user=admin</argument>
<argument>--passwordfile=${user.home}/.asadminpass</argument>
<argument>--host=testserver</argument>
<argument>--port=4848</argument>
<argument>target/spring-ejb-jar-with-dependencies.jar</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
[...]
We do have two different profiles aiming at two different servers, one being our internal testbed / staging system, the other one our production environment. There are two caveats to take care of, here:
Done so, the module can be deployed to the servers using
[...]
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1EA1</version>
<scope>provided</scope>
</dependency>
[...]
By then the @WebService / @WebMethod annotations were usable in the EJB code and the web service got deployed and started well.
), care should be taken in order to configure the deployment profiles according to your local settings (regarding the path configuration of asadmin, the server host name and login credentials) before the application might be built and deployed without further modifications. Though, as pointed out, some (all?) of the approaches provided in here possibly could be beautified, this might serve as a working skeleton for building Spring-enabled, maven-managed EJB3 modules. Things we discovered in course of getting here:
| ejb3-spring.tar.gz | ![]() |
2501 bytes |