Application servers and environments supported by Weld
Using Weld with WildFly
WildFly comes with pre-configured Weld. There is no configuration needed to use Weld (or CDI for that matter). You may still want to fine-tune Weld with additional configuration settings .
GlassFish
Weld is also built into GlassFish. Since GlassFish is the Jakarta EE compatible implementation, it supports all features of CDI. What better way for GlassFish to support these features than to use Weld, the CDI compatible implementation? Just package up your CDI application and deploy.
Servlet containers (such as Tomcat or Jetty)
While CDI does not require support for servlet environments, Weld can be used in a servlet container, such as Tomcat, Undertow or Jetty.
Note
|
There is a major limitation to using a servlet container; Weld doesn’t
support deploying session beans, injection using @EJB
or @PersistenceContext , or using transactional events in servlet
containers. For enterprise features such as these, you should really be
looking at a Jakarta EE application server.
|
Weld can be used as a library in a web application that is deployed to
a Servlet container. You should add the weld-servlet-core
as a dependency
to your project:
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>6.0.1.Final</version>
</dependency>
All the necessary dependencies (CDI API, Weld core) will be fetched transitively.
Alternatively, there is a shaded version with all the dependencies in a single jar file which is available as:
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-shaded</artifactId>
<version>6.0.1.Final</version>
</dependency>
In general, weld-servlet uses ServletContainerInitializer mechanism to hook into the life cycle of Servlet 5.x compatible containers.
In special cases when your Servlet container does not support ServletContainerInitializer
or you need more control over the ordering of listeners (e.g. move Weld’s listener
to the beginning of the list so that CDI context are active during invocation of other listeners),
you can register Weld’s listener manually in the WEB-INF/web.xml
file of the application:
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
Note
|
There is quite a special use-case where one more special component must
be involved. If you want the session context to be active during
HttpSessionListener.sessionDestroyed() invocation when the session
times out or when all the sessions are destroyed because the deployment
is being removed then org.jboss.weld.module.web.servlet.WeldTerminalListener must
be specified as the last one in your web.xml . This listener activates
the session context before other listeners are invoked (note that the
listeners are notified in reverse order when a session is being
destroyed).
|
When working with multiple deployments in servlet environment, Weld Servlet
allows defining context identifier per application deployed. Each different
context identifier will create a new Weld container instance. If not specified,
Weld falls back to the default value - STATIC_INSTANCE
. While using custom
identifiers is neither required nor commonly used, it certainly has some use-cases.
For instance managing several deployments with Arquillian Tomcat container.
Setting the identifier is as simple as adding one context parameter into web.xml
:
<context-param>
<param-name>WELD_CONTEXT_ID_KEY</param-name>
<param-value>customValue</param-value>
</context-param>
Tomcat
Tomcat 10.1, which implements Servlet 5.0 specification, is supported.
Binding BeanManager to JNDI
Binding BeanManager to JNDI does not work out of the box.
Tomcat has a read-only JNDI, so Weld can’t automatically bind the
BeanManager extension SPI. To bind the BeanManager into JNDI, you should
populate META-INF/context.xml
in the web root with the following
contents:
<Context>
<Resource name="BeanManager"
auth="Container"
type="jakarta.enterprise.inject.spi.BeanManager"
factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>
and make it available to your deployment by adding this to the bottom
of web.xml
:
<resource-env-ref>
<resource-env-ref-name>BeanManager</resource-env-ref-name>
<resource-env-ref-type>
jakarta.enterprise.inject.spi.BeanManager
</resource-env-ref-type>
</resource-env-ref>
Tomcat only allows you to bind entries to java:comp/env
, so the
BeanManager will be available at java:comp/env/BeanManager
Embedded Tomcat
With embedded Tomcat it is necessary to register Weld’s listener programmatically:
public class Main {
public static void main(String[] args) throws ServletException, LifecycleException {
Tomcat tomcat = new Tomcat();
Context ctx = tomcat.addContext("/", new File("src/main/resources").getAbsolutePath());
Tomcat.addServlet(ctx, "hello", HelloWorldServlet.class.getName());
ctx.addServletMapping("/*", "hello");
ctx.addApplicationListener(Listener.class.getName()); # (1)
tomcat.getConnector();
tomcat.start();
tomcat.getServer().await();
}
public static class HelloWorldServlet extends HttpServlet {
@Inject
private BeanManager manager;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().append("Hello from " + manager);
}
}
}
-
Weld’s
org.jboss.weld.environment.servlet.Listener
registered programmatically
Jetty
Note
|
There is currently no regular testing for Jetty. Therefore, take the information provided here with a pinch of salt. Consult Jetty documentation and examples for more details on how to run Jetty with Weld. |
Jetty 12 and newer are supported. Context activation/deactivation and dependency injection into Servlets, Filters and Servlet listeners works out of the box.
No further configuration is needed when starting Jetty as an embedded webapp server from within another Java program. However, if you’re using a Jetty standalone instance, there is one more configuration step that is required.
Jetty ee10-cdi
Module
The Weld/Jetty integration uses the Jetty ee10-cdi
module.
To activate this module in Jetty, the argument --add-modules=ee10-cdi
needs to be added to the
command line, which can be done for a standard distribution by running the commands:
cd $JETTY_BASE java -jar $JETTY_HOME/start.jar --add-modules=ee10-cdi
Undertow
Weld supports context activation/deactivation and dependency injection into Servlets when running on Undertow. Weld’s listener needs to be registered programmatically:
public class Main {
public static void main(String[] args) throws ServletException {
DeploymentInfo servletBuilder = Servlets.deployment()
.setClassLoader(Main.class.getClassLoader())
.setResourceManager(new ClassPathResourceManager(Main.class.getClassLoader()))
.setContextPath("/")
.setDeploymentName("test.war")
.addServlet(Servlets.servlet("hello", HelloWorldServlet.class).addMapping("/*"))
.addListener(Servlets.listener(Listener.class)); # (1)
DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
manager.deploy();
HttpHandler servletHandler = manager.start();
PathHandler path = Handlers.path(Handlers.redirect("/")).addPrefixPath("/", servletHandler);
Undertow server = Undertow.builder().addHttpListener(8080, "localhost").setHandler(path).build();
server.start();
}
public static class HelloWorldServlet extends HttpServlet {
@Inject BeanManager manager;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().append("Hello from " + manager);
}
}
}
-
Weld’s
org.jboss.weld.environment.servlet.Listener
registered programmatically:
Bean Archive Isolation
By default, bean archive isolation is enabled. It means that alternatives, interceptors and decorators can be selected/enabled for a bean archive by using a beans.xml descriptor.
This behaviour can be changed by setting the servlet initialization parameter org.jboss.weld.environment.servlet.archive.isolation
to false.
In this case, Weld will use a "flat" deployment structure - all bean classes share the same bean archive and all beans.xml descriptors are automatically merged into one. Thus alternatives, interceptors and decorators selected/enabled for a bean archive will be enabled for the whole application.
Implicit Bean Archive Support
CDI 4 changed the default discovery mode to annotated
(see also
Packaging and deployment
.
In order to help with performance during bootstrap, Weld Servlet supports the use of Jandex bytecode scanning library to speed up the scanning process. Simply put the jandex.jar on the classpath.
If Jandex is not found on the classpath Weld will use the Java Reflection as a fallback.
In general, an implicit bean archive does not have to contain a beans.xml descriptor. However, such a bean archive is not supported by Weld Servlet, i.e. it’s excluded from discovery.
Note
|
The bean discovery mode of annotated is the default mode since Weld 5/CDI 4. Previous versions of Weld/CDI defaulted to all discovery mode.
|
Servlet Container Detection
Weld servlet container integration is delivered as a single artifact, so that it’s possible to include this artifact in a war and deploy the application to any of the supported servlet containers.
This approach has advantages but also drawbacks.
One of them is the fact that Weld attempts to detect the servlet container automatically.
While this works most of the time, there are few rare cases, when it might be necessary to specify the container manually by setting the servlet initialization parameter org.jboss.weld.environment.container.class
to:
-
org.jboss.weld.environment.tomcat.TomcatContainer
-
org.jboss.weld.environment.jetty.JettyContainer
-
org.jboss.weld.environment.undertow.UndertowContainer
-
or any custom
org.jboss.weld.environment.Container
implementation
Java SE
In addition to improved integration of the Enterprise Java stack, the "Contexts and Dependency Injection for the Java EE platform" specification also defines a state of the art typesafe, stateful dependency injection framework, which can prove useful in a wide range of application types. To help developers take advantage of this, Weld provides a simple means for being executed in the Java Standard Edition (SE) environment independently of any Java EE APIs.
When executing in the SE environment the following features of Weld are available:
-
Managed beans with
@PostConstruct
and@PreDestroy
lifecycle callbacks -
Dependency injection with qualifiers and alternatives
-
@ApplicationScoped
,@Dependent
and@Singleton
scopes -
Interceptors and decorators
-
Stereotypes
-
Events
-
Portable extension support
EJB beans are not supported.
CDI SE Module
Weld provides an extension which will boot a CDI bean manager in Java SE, automatically registering all simple beans found on the classpath. The command line parameters can be injected using either of the following:
@Inject @Parameters List<String> params;
@Inject @Parameters String[] paramsArray;
The second form is useful for compatibility with existing classes.
Note
|
The command line parameters do not become available for injection until
the ContainerInitialized event is fired. If you need access to the
parameters during initialization you can do so via the
public static String[] getParameters() method in StartMain .
|
Here’s an example of a simple CDI SE application:
import jakarta.inject.Singleton;
@Singleton
public class HelloWorld
{
public void printHello(@Observes ContainerInitialized event, @Parameters List<String> parameters) {
System.out.println("Hello " + parameters.get(0));
}
}
Note
|
Weld automatically registers shutdown hook during initialization in order to properly terminate all running containers should the VM be terminated or program exited.
Even though it’s possible to change this behavior (either by setting a system property org.jboss.weld.se.shutdownHook to false or through the Weld.property() method) and register an alternative hook and implement the logic, it is not recommended.
The behavior across OS platforms may differ and specifically on Windows it proves to be problematic.
|
Bootstrapping CDI SE
CDI SE applications can be bootstrapped in the following ways.
The ContainerInitialized
Event
Thanks to the power of CDI’s typesafe event model, application
developers need not write any bootstrapping code. The Weld SE module
comes with a built-in main method which will bootstrap CDI for you and
then fire a ContainerInitialized
event. The entry point for your
application code would therefore be a simple bean which observes the
ContainerInitialized
event, as in the previous example.
In this case your application can be started by calling the provided main method like so:
java org.jboss.weld.environment.se.StartMain <args>
Programmatic Bootstrap API
For added flexibility, CDI SE also comes with a bootstrap API which can
be called from within your application in order to initialize CDI and
obtain references to your application’s beans and events. The API
consists of two classes: Weld
and WeldContainer
.
/** A builder used to bootsrap a Weld SE container. */
public class Weld extends SeContainerInitializer implements ContainerInstanceFactory
{
/** Boots Weld and creates and returns a WeldContainer instance, through which
* beans and events can be accesed. */
public WeldContainer initialize() {...}
/** Convenience method for shutting down all the containers initialized by a specific builder instance. */
public void shutdown() {...}
}
/** Represents a Weld SE container. */
public class WeldContainer extends AbstractCDI<Object> implements AutoCloseable, ContainerInstance, SeContainer
{
/** Provides access to all events within the application. */
public Event<Object> event() {...}
/** Provides direct access to the BeanManager. */
public BeanManager getBeanManager() {...}
/** Returns the identifier of the container */
String getId() {...}
/** Shuts down the container. */
public void shutdown() {...}
/** Returns the running container with the specified identifier or null if no such container exists */
public static WeldContainer instance(String id) {...}
}
Here’s an example application main method which uses this API to
bootsrap a Wedl SE container and call a business method of a bean MyApplicationBean
.
import org.jboss.weld.environment.se.Weld;
public static void main(String[] args) {
Weld weld = new Weld();
WeldContainer container = weld.initialize();
container.select(MyApplicationBean.class).get().callBusinessMethod();
container.shutdown();
}
Alternatively the application could be started by firing a custom event
which would then be observed by another simple bean. The following
example fires MyEvent
on startup.
org.jboss.weld.environment.se.Weld;
public static void main(String[] args) {
Weld weld = new Weld();
WeldContainer container = weld.initialize();
container.event().select(MyEvent.class).fire( new MyEvent() );
// When all observer methods are notified the container shuts down
container.shutdown();
}
Because WeldContainer
implements AutoCloseable
, it can be used within a
try-with-resources block. Should the execution get out of the code block,
the Weld instance is shut down and all managed instances
are safely destroyed. Here is an example using the above code but
leaving out the shutdown()
method:
org.jboss.weld.environment.se.Weld;
public static void main(String[] args) {
Weld weld = new Weld();
try (WeldContainer container = weld.initialize()) {
container.select(MyApplicationBean.class).get().callBusinessMethod();
}
}
In case of more complex scenarios, it might be handy to gain higher level of control over the bootstraping process. Using the builder, it is possible to disable automatic scanning and to explicitly select classes/packages which will be managed by Weld. Interceptors, decorators and extensions can be defined in the very same manner. Last but not least, builder can be used to set Weld-specific configuration. Following example demonstrates these features:
Weld weld = new Weld()
.disableDiscovery()
.packages(Main.class, Utils.class)
.interceptors(TransactionalInterceptor.class)
.property("org.jboss.weld.construction.relaxed", true);
try (WeldContainer container = weld.initialize()) {
MyBean bean = container.select(MyBean.class).get();
System.out.println(bean.computeResult());
}
Furthermore, it is also possible to create several independent Weld instances. Code snippet below shows how to achieve that:
Weld weld = new Weld()
.disableDiscovery();
weld.containerId("one").beanClasses(MyBean.class).initialize();
weld.containerId("two").beanClasses(OtherBean.class).initialize();
MyBean bean = WeldContainer.instance("one").select(MyBean.class).get();
System.out.println(bean.computeResult());
// Shutdown the first container
WeldContainer.instance("one").shutdown();
// Shutdown all the containers initialized by the builder instance
weld.shutdown();
Request Context
Weld introduces an @ActivateRequestContext
interceptor binding which enables you to explicitly activate the request context and use @RequestScoped
beans in Java SE.
The following example shows how to achieve that:
public class Foo {
@Inject
MyRequestScopedBean bean;
@ActivateRequestContext
public void executeInRequestContext() {
bean.ping()
}
}
Thread Context
In contrast to Java EE applications, Java SE applications place no
restrictions on developers regarding the creation and usage of threads.
Therefore Weld SE provides a custom scope annotation, @ThreadScoped
,
and corresponding context implementation which can be used to bind bean
instances to the current thread. It is intended to be used in scenarios
where you might otherwise use ThreadLocal
, and does in fact use
ThreadLocal
under the hood.
To use the @ThreadScoped
annotation you need to enable the
RunnableDecorator
which 'listens' for all executions of
Runnable.run()
and decorates them by setting up the thread context
beforehand, bound to the current thread, and destroying the context
afterwards.
<beans>
<decorators>
<class>org.jboss.weld.environment.se.threading.RunnableDecorator</class>
</decorator>
</beans>
Another option how to use thread context is to enable it at class or method
level by @ActivateThreadScope
interceptor binding and related ActivateThreadScopeInterceptor
.
public class Foo {
@Inject
MyThreadScopedBean bean;
@ActivateThreadScope
public void executeInThreadContext() {
bean.ping()
}
}
Note
|
It is not necessary to use @ThreadScoped in all multithreaded
applications. The thread context is not intended as a replacement for
defining your own application-specific contexts. It is generally only
useful in situations where you would otherwise have used ThreadLocal
directly, which are typically rare.
|
Setting the Classpath
Weld SE comes packaged as a 'shaded' jar which includes the CDI API,
Weld Core and all dependent classes bundled into a single jar. Therefore
the only Weld jar you need on the classpath, in addition to your
application’s classes and dependent jars, is the Weld SE jar. If you are
working with a pure Java SE application you launch using java
, this
may be simpler for you.
If you prefer to work with individual dependencies, then you can use the
weld-se-core
jar which just contains the Weld SE classes. Of course in
this mode you will need to assemble the classpath yourself.
If you work with a dependency management solution such as Maven you can declare a dependency such as:
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-shaded</artifactId>
</dependency>
Bean Archive Isolation
By default, bean archive isolation is enabled. It means that alternatives, interceptors and decorators can be selected/enabled for a bean archive by using a beans.xml descriptor.
This behaviour can be changed by setting a system property org.jboss.weld.se.archive.isolation
to false
or through the Weld.property()
method.
In this case, Weld will use a "flat" deployment structure - all bean classes share the same bean archive and all beans.xml descriptors are automatically merged into one. Thus alternatives, interceptors and decorators selected/enabled for a bean archive will be enabled for the whole application.
Tip
|
All Weld SE specific configuration properties could be also set through CDI API, i.e. using SeContainerInitializer.addProperty() and SeContainerInitializer.setProperties() methods.
|
Implicit Bean Archive Support
CDI 4 changed the default discovery mode to annotated
(see also
Packaging and deployment
. This mode may bring additional overhead during container bootstrap.
In order to help with performance during bootstrap, Weld supports the use of Jandex bytecode scanning library to speed up the scanning process. Simply put the jandex.jar on the classpath.
If Jandex is not found on the classpath Weld will use the Java Reflection as a fallback.
By default, an implicit bean archive that does not contain a beans.xml descriptor is excluded from discovery.
However, it is possible to instruct Weld to scan all class path entries and discover such archive.
You can do so by setting Weld system property org.jboss.weld.se.scan.classpath.entries
or CDI system property jakarta.enterprise.inject.scan.implicit
to true
.
Another approach is to use Weld.property()
and SeContainerInitializer.addProperty()
methods.
Note
|
The bean discovery mode of annotated is the default mode since Weld 5/CDI 4. Previous versions of Weld/CDI defaulted to all discovery mode.
|
Extending Bean Defining Annotations
If you are running with discovery mode annotated
, then only classes with bean defining annotations will be picked up as beans.
The set of these annotations is given by CDI but Weld SE allows you to expand it via Weld.addBeanDefiningAnnotations(Class<? extends Annotation>… annotations)
.
Any annotation added this way will be considered a bean defining annotation when performing discovery.
Just note that added annotations are ignored if you are also using <trim/>
option or Weld configuration key org.jboss.weld.bootstrap.vetoTypesWithoutBeanDefiningAnnotation
.
Weld SE and Weld Servlet cooperation
Sometimes it could be convenient to start Servlet container programmatically.
In this case a cooperation with Weld SE might come handy.
This cooperation is based on passing Weld
, WeldContainer
or BeanManager
instance to ServletContext
.
You can either set a context attribute or use org.jboss.weld.environment.servlet.Listener
.
Check following examples; some of them are using Tomcat syntax, others are using Jetty.
Not all approaches might be supported by all servlets.
For instance, not all servlets might allow to register an already instantiated listener.
Adding WeldContainer
instance as a context attribute on Tomcat Embedded:
try (WeldContainer weld = new Weld().disableDiscovery().beanClasses(Cat.class).initialize()) {
// start the servlet in some basic configuration
Tomcat tomcat = new Tomcat();
tomcat.getConnector();
Context context = tomcat.addContext("", new File(".").getAbsolutePath());
String servletName = TestServlet.class.getSimpleName();
tomcat.addServlet("", servletName, TestServlet.class.getName());
context.addServletMappingDecoded("/test", servletName);
// register Weld Listener and set Container instance as an attribute
context.addApplicationListener(Listener.class.getName());
context.getServletContext().setAttribute(Listener.CONTAINER_ATTRIBUTE_NAME, container);
// start the server
tomcat.start();
}
Adding BeanManager
instance as a context attribute using Jetty:
Weld weld = new Weld();
WeldContainer container = weld.initialize();
Server server = new Server(8080);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(TestServlet.class, "/test");
context.setAttribute(WeldServletLifecycle.BEAN_MANAGER_ATTRIBUTE_NAME, container.getBeanManager());
server.start();
Adding Weld
instance as event listener with usage of org.jboss.weld.environment.servlet.Listener
:
Weld builder = new Weld().disableDiscovery().beanClasses(Cat.class);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.addEventListener(Listener.using(builder));
Server server = new Server(8080);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(TestServlet.class, "/test");
server.start();
OSGi
Weld supports OSGi environment through Pax CDI. For more information on using Weld in OSGi environment check Pax CDI documentation. If you wish to see some examples, there is plenty of them in Pax CDI repository.