CDI használata Java SE alkalmazásban

Posted by | · · · | Egy csésze kávé | Nincs hozzászólás a(z) CDI használata Java SE alkalmazásban bejegyzéshez

A “Contexts and Dependency Injection for the Java EE platform” specifikációja szerint a CDI előnyeit felhasználhatjuk Java SE alkalmazásban is. A CDI reference implementation honlapján ezt olvashatjuk: “Weld can also be used in a Servlet-only environment (Tomcat, Jetty) or plain Java SE environment.”

 

Erre felbuzdulva meg is próbáltam CDI-t használó Java SE alkalmazást készíteni. Az alábbiakban megosztanám tapasztalataimat.

 

A dokumentáció szerint az alábbi három lépésre van szükségünk:

  • Hozzáadni a projektünkhöz a weld-se dependency-t:
    <dependency>
        <groupId>org.jboss.weld.se</groupId>
        <artifactId>weld-se</artifactId>
        <version>2.3.2.Final</version>
    </dependency>
    
  • Létrehozni a beans.xml fájlt a META-INF mappában:
    <beans xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd" >
    </beans>
    
  • CDI SE alkalmazás két módon bootstappelhető:
    • Bootstrapping code írására nincs is szükségünk, a weld-se dependency rendelkezik egy main osztállyal (org.jboss.weld.environment.se.StartMain), mely elindítja a CDI container-t. Nekünk csupán a ContainerInitialized eseményre kell figyelnünk.
    • CDI container-t magunk is indíthatunk a Bootstrap API-val (Weld és WeldContainer).

Ennek fényében a “Hello world” programomat meg is írtam:

import java.util.List;
import javax.enterprise.event.Observes;
import javax.inject.Singleton;
import org.jboss.weld.environment.se.bindings.Parameters;
import org.jboss.weld.environment.se.events.ContainerInitialized;

@Singleton
public class Application {

    public void printHello(
            @Observes ContainerInitialized event,
            @Parameters List<String> parameters) {
        System.out.println("Hello world!");
    }
}

Ezt követően Netbeans-ben beállítottam a Main class-t (org.jboss.weld.environment.se.StartMain), majd elindítottam az alkalmazást, melynek kimenete a következő volt:

Jan 02, 2016 7:01:06 PM org.jboss.weld.bootstrap.WeldStartup 
INFO: WELD-000900: 2.3.2 (Final)
Jan 02, 2016 7:01:07 PM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Jan 02, 2016 7:01:08 PM org.jboss.weld.environment.se.WeldContainer initialize
INFO: WELD-ENV-002003: Weld SE container STATIC_INSTANCE initialized
Hello world!
Weld SE container STATIC_INSTANCE shut down by shutdown hook

Nagyszerű, működik a hello world programom.

 

A következő teendőm az, hogy készítek egy futtatható jar-t (olyan jar-t, amely tartalmazza a függőségeket). Erre a maven-assembly-plugin alkalmas.

<profiles>
    <profile>
        <id>jar-with-dependencies</id>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.5.4</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>org.jboss.weld.environment.se.StartMain</mainClass>
                                <addClasspath>true</addClasspath>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-my-jar-with-dependencies</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Az így létrehozott jar futtatásakor azonban a következő kivételt kaptam:
java.lang.ClassNotFoundException: javax.servlet.http.HttpServletRequest
Megnéztem a létrehozott jar-t és valóban nem szerepelt benne. Majd megnéztem a weld-se jar-t is, s ott sem szerepel.

 

Némi keresgélés után a következő bug report-ra bukkantam: Weld SE – Startup fails if all classes bundled within a single jar. Bár a kivétel nem ugyanaz, gondoltam mégiscsak megpróbálom a tanácsolt megoldást. A megoldás, amit ajánlanak az, hogy a bean felderítés folyamatából a weld-es osztályokat kizárjuk (Weld FAQ – How can I bundle my entire SE application with Weld into a single jar?). Ezt a következő beans.xml-el tehetjük meg:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all">
    <scan>
        <exclude name="org.jboss.weld.**" />
    </scan>
</beans>

Ezt követően a helyzet javult, lefutott a program, de a következő kimenettel:

Jan 02, 2016 10:25:55 PM org.jboss.weld.bootstrap.WeldStartup 
INFO: WELD-000900: 2.3.2 (Final)
Jan 02, 2016 10:25:56 PM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Jan 02, 2016 10:25:57 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.logging.JBossLogManagerLogger because of underlying class loading error: Type org.jboss.logmanager.Level not found.  If this is unexpected, enable DEBUG logging to see the full error.
Jan 02, 2016 10:25:57 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.logging.JBossLogManagerProvider because of underlying class loading error: Type org.jboss.logmanager.Logger$AttachmentKey not found.  If this is unexpected, enable DEBUG logging to see the full error.
Jan 02, 2016 10:25:58 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.logging.Log4jLogger because of underlying class loading error: Type org.apache.log4j.Priority not found.  If this is unexpected, enable DEBUG logging to see the full error.
Jan 02, 2016 10:25:59 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.logging.Log4j2Logger because of underlying class loading error: Type org.apache.logging.log4j.message.Message not found.  If this is unexpected, enable DEBUG logging to see the full error.
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface com.google.common.util.concurrent.ListenableFuture<com.google.common.util.concurrent.ListenableFuture<? extends V>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.util.concurrent.AsyncSettableFuture$NestedFuture
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type com.google.common.util.concurrent.AbstractFuture<com.google.common.util.concurrent.ListenableFuture<? extends V>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.util.concurrent.AsyncSettableFuture$NestedFuture
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface java.util.concurrent.Future<com.google.common.util.concurrent.ListenableFuture<? extends V>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.util.concurrent.AsyncSettableFuture$NestedFuture
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface java.lang.Comparable>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.collect.Cut$BelowAll
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type com.google.common.collect.Cut<java.lang.Comparable<?>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.collect.Cut$BelowAll
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface java.util.Map<com.google.common.reflect.TypeToken<? extends B>,B> ignored on [EnhancedAnnotatedTypeImpl] public final  class com.google.common.reflect.MutableTypeToInstanceMap
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type com.google.common.collect.ForwardingMap<com.google.common.reflect.TypeToken<? extends B>, B> ignored on [EnhancedAnnotatedTypeImpl] public final  class com.google.common.reflect.MutableTypeToInstanceMap
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface java.util.Map<java.lang.Class<?>,class javax.el.BeanELResolver$BeanProperties> ignored on [EnhancedAnnotatedTypeImpl] private static  class javax.el.BeanELResolver$SoftConcurrentHashMap
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type java.util.concurrent.ConcurrentHashMap<java.lang.Class<?>, javax.el.BeanELResolver$BeanProperties> ignored on [EnhancedAnnotatedTypeImpl] private static  class javax.el.BeanELResolver$SoftConcurrentHashMap
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface java.util.concurrent.ConcurrentMap<java.lang.Class<?>,class javax.el.BeanELResolver$BeanProperties> ignored on [EnhancedAnnotatedTypeImpl] private static  class javax.el.BeanELResolver$SoftConcurrentHashMap
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type class java.util.AbstractMap<java.lang.Class<?>,class javax.el.BeanELResolver$BeanProperties> ignored on [EnhancedAnnotatedTypeImpl] private static  class javax.el.BeanELResolver$SoftConcurrentHashMap
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type interface java.lang.Comparable>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.collect.Cut$AboveAll
Jan 02, 2016 10:26:00 PM org.jboss.weld.util.Beans omitIllegalBeanTypes
INFO: WELD-001125: Illegal bean type com.google.common.collect.Cut<java.lang.Comparable<?>> ignored on [EnhancedAnnotatedTypeImpl] private final static  class com.google.common.collect.Cut$AboveAll
Jan 02, 2016 10:26:01 PM org.jboss.weld.environment.se.WeldContainer initialize
INFO: WELD-ENV-002003: Weld SE container STATIC_INSTANCE initialized
Hello world!
Weld SE container STATIC_INSTANCE shut down by shutdown hook

Azonban ez a sok “Not generating any bean definitions” és “Illegal bean type interface” nem tetszett, még akkor sem, ha a log level INFO.

 

Mivel azonban a bug report-ban szereplő kivétel nem tartalmazott “ClassNotFoundException”-t, így inkább visszatértem a korábbi állapotra és kipróbáltam, hogy mi van, ha hozzáadom a javas.servlet dependency-t a projekthez. Ekkor természetesen mást hiányolt. Úgyhogy ez az elkeseredett próbálkozás nagyon hamar zátonyra futott.

 

Ezt követően arra tettem kísérletet, hogy az összes függőséget egy lib mappába másoltatom a maven-dependency-plugin-nal:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>org.jboss.weld.environment.se.StartMain</mainClass>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <phase>install</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Ezen ötletnek köszönhetően végre minden probléma nélkül elindult és lefutott az alkalmazás:

Jan 03, 2016 11:02:04 AM org.jboss.weld.bootstrap.WeldStartup 
INFO: WELD-000900: 2.3.2 (Final)
Jan 03, 2016 11:02:05 AM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Jan 03, 2016 11:02:06 AM org.jboss.weld.environment.se.WeldContainer initialize
INFO: WELD-ENV-002003: Weld SE container STATIC_INSTANCE initialized
Hello world!
Weld SE container STATIC_INSTANCE shut down by shutdown hook

Sajnos magyarázatot nem tudok arra adni, hogy a függőségeket tartalmazó nagy jar miért nem működik, viszont a külön lib mappába másolt függőségek megoldás miért igen.

 


No Comments

Leave a comment