What we have learnt so far can be enough for configuring many kinds of applications. If you are using a complex archive configuration, such as an EAR archive with several modules and dependencies, it would prove useful to define your classloading strategy in a single file.
The configuration file
jboss-deployment-structure.xml can do exactly this. The advantages of using this file are many:
Let’s see with some practical examples what jboss-deployment-structure.xml can do for you.
Setting up a single module dependency
We have already learnt how to activate a log4j dependency, using the Dependencies attribute in the archive’s MANIFEST file. The same effect can be achieved by using the jboss-deployment-structure.xml file. Let’s recap the archive structure, which is basically made up of a web application named
As you can see, the file jboss-deployment-structure.xml needs to be placed within the META-INF folder of the EAR.
Here’s its content:
The file jboss-deployment-structure is not for exclusive use of EARs; as a matter of fact, you could also deploy it ithin the WebApp application by placing it within the WEB-INF folder of the archive. It is, however, applicable only as top-level archive. Thus, if a jboss-deployment-structure.xml is placed in the WAR’s WEB-INF folder and the WAR is packaged in a EAR archive, then the jboss-deployment-structure.xml is ignored.
The relevant part of this file is the sub-deployment element, which references the web application, including within it the dependencies element. The expected outcome is that the application server will trigger the dependency to log4j Api, which will therefore be visible by our web application.
Excluding the server automatic dependencies
Earlier in this tutorial, we have shown how the application server is able to trigger some dependencies, automatically, when some conditions are met. For example, if you deploy a JSF application (containing the faces-config.xml file), then the JSF 2.1 Api implementation is automatically added.
This might not always be the desired option, for example, because you want to provide another release implementation for that module. You can easily achieve this using the exclusion section in the
jboss-deployment-structure.xml, as shown here:
Notice in the dependencies section we have added our alternate JSF 1.2 implementation, which will be used by your application. Actually, this JSF implementation ships with the application server distribution along with the javax.faces.api module path, under the folder specified by the slot attribute. In our case, this corresponds to the JBOSS_HOME/modules/javax/faces/api/1.2 folder.
Supposing you have an application that is made up of a web application, an EJB module, and a JAR file containing utility classes. All sub-deployments are placed at the root of the archive, so that they will be able to see each other. This can be convenient, however, supposing that your web application itself contains some implementations of the same EJB. That’s absolutely possible since Java EE 6 specification allows your web application to include EJB classes within the WEB-INF/classes or WEB-INF/lib folder.
How does the classloader solves this conflict? The application server classloader has a priority list when loading classes that are used to avoid any conflict between loaded classes.
So, in this example, the EJB libraries located in the WEB-INF folder will “hide” the implementations of EJB.jar top-level deployment. Whether or not this is the desired action from the container, you can still override it:
In this example, we have added a dependency to the EJB.jar, which is placed at the root of the archive and which will override the implementation packed within the web application.
Notice the ear-subdeployments-isolated element placed at the top of the file. By setting the EAR isolation level, you will be able to indicate if the sub-deployments modules are visible to each other.
The default value for this attribute is false, meaning that the sub-deployment modules will be able to see each other. If you are setting isolation to true, each module will then be picked up by a different classloader, so, in our example, the web application will not be able to find the classes contained in the EJB.jar and Utility.jar library.
If you want to keep deployment isolated, but allow visibility for some of them, then you have two choices available:
From the following image, you can see how you could correctly set up your EAR, by placing common libraries in the lib folder, and adding a dependency to the EJB classes:
And this is the corresponding configuration required in jboss-deployment-structure.xml:
Using Class-Path declaration to solve dependencies
Until now, we have solved dependencies between modules using JBoss’ way, which we obviously suggest as first choice. Nevertheless, we should also account for Java’s portable way to reference one or more library included in the EAR file.
This can be done using the Class-Path attribute in the
MANIFEST.MF file of a module, which needs to reference another library that could not be otherwise visible to the application (think back to the earlier example of a deployment unit with isolation set to true).
For example, supposing you needed to reference the Utility.jar application from within your web application, then simply add to your META-INF/MANIFEST.MF the following:
Manifest-Version: 1.0 Class-Path: Utility.jar
You can actually include more than one library to the Class-Path, keeping them separated by a comma, much the same way you did with the JBoss’ Dependencies attribute.
Choosing between Class-Path approach and JBoss’ Dependencies approach is a matter of how your application is structured: using JBoss’ Dependencies buys you a richer set of options, in particular the ability to export the Dependencies to other deployments, as we have shown earlier. One more point in favor of the JBoss’ Dependencies approach is the ability to reference modules that are not actually packaged within the application; for example, we have seen how to add a dependency to log4j API that are part of the server distribution.
On the other hand, the main advantage of the Class-Path approach relies on application portability. Thus, if a full-portable solution is a priority for you, you could consider switching to the Class-Path manifest attribute.
Ravindra Savaram is a Content Lead at Mindmajix.com. His passion lies in writing articles on the most popular IT platforms including Machine learning, DevOps, Data Science, Artificial Intelligence, RPA, Deep Learning, and so on. You can stay up to date on all these technologies by following him on LinkedIn and Twitter.