In my last article, I discussed the nature of EAR files, what they support, what they do not support, and how to configure dependency utility libraries using the manifest
Class-Path: entry within a JAR file. This article intends to expand upon the discussion of J2EE packaging issues by focusing on the approaches that vendors can use for implementing EAR classloaders. Additionally, this article will point out an ambiguity that exists in the J2EE specification that allows vendors to implement EAR classloading schemes differently.
With any application that needs to have a JSP/servlet access an EJB, the JSP/servlet needs to be able to load the classes it needs to work with the EJB. When a standalone application is deployed, it is done so in its own classloader. This means that if you deploy a Web application (WAR) and an EJB application (JAR) separately, the respective classes for each application will be loaded in different classloaders that are siblings of one another. The classes in the Web application classloader will not be visible to the classes in the other application's classloader. This creates a problem for Web applications that want to use EJBs that are deployed separately. In fact, prior to EAR files, many developers would deploy an EJB and then repackage the same EJB JAR as part of the
WEB-INF\lib directory of the Web application. The same class files would exist in two different places, so that the overall application could work correctly. Gross.
EAR applications were introduced to solve this very problem. EAR files are not merely a convenient packaging format, but they provide for a special classloading scheme that allows applications within the EAR file to view the classes of other applications.
What's interesting about the J2EE 1.3 specification is that it doesn't make any specific requirements as to the structure of how an EAR classloader might work. Given this flexibility allowed by the specification, an application server vendor has an incredible amount of flexibility in deciding how classes should be loaded. For example, some questions that a vendor needs to ask before implementing an EAR classloader include:
Follow-up with Tyler with your questions.
Also in EJB 2:
log4j.jar, should the
log4j.jarbe loaded in a parent classloader and then the EJB applications loaded in a child classloader, so that appropriate visibility is maintained?
Prior to EJB 2.0 Public Final Draft 2, vendors had a lot of flexibility in choosing how to set up a classloading scheme. JSPs/servlets that needed to make use of an EJB only needed to be able to load the home interface, remote interface, common classes, and stub classes of the EJB. The common classes, such as exceptions and parameters, should be placed into a dependency JAR file and loaded as part of the manifest
Class-Path: entry. This requires vendors to determine a way for a Web application that depends upon an EJB to load the home interface, remote interface, and stubs.
Please refer to Figure 1: Simple Classloading Approach for a graphical representation of a simple classloading scheme that a vendor could implement. In this model, each EAR application would be loaded by a custom EAR classloader instance. EJB applications and Web applications would each be loaded by custom classloaders that are children of the EAR classloader. In this scheme, any class file that needs to be shared by more than one application in the EAR will be loaded by the EAR classloader. Any files loaded at the EAR classloader level are automatically visible to all classes loaded by children classloaders.
In this scenario, all EJB applications are loaded by a single EJB classloader that is a child of the EAR classloader. Even if you have different EJB JAR files, they will all be loaded by the same classloader. This is done to facilitate EJB-EJB communication between EJBs in different applications, but hosted on the same virtual machine. Also in this scenario, each Web application is loaded in a different classloader to maintain class isolation. For example, if every Web application has an
index.jsp, when that JSP is converted into a servlet, that servlet could have the same class name as the equivalent servlets for the
index.jsps in the other Web applications. Each Web application needs to be able to load its own version of that servlet, so each Web application is isolated in its own classloader.
In order for Web applications to make use of EJBs deployed in the same EAR file, the Web applications need to have visibility to the external interfaces and stub implementation classes of those EJBs. Since the EJB and Web application classloaders are siblings in this scenario, the Web applications do not have direct visibility to the right class files. So to solve this problem, the EJB classloader can take all of the public interfaces of each of the EJBs and their stub implementation files and "export" them to the EAR classloader where they'll be visible by all applications in the EAR. The Web applications will then be able to readily load the classes needed to use any EJB.
Additionally, dependency utility libraries can be loaded in different places based upon where the library is specified. If a single Web application lists a dependency library in its
WEB-INF\lib directory, then that library is unique to that Web application. There is no need for other applications to access the contents of that library and it should not be loaded by the EAR classloader. In this situation, the Web application custom classloader will load the utility JAR file. Other Web applications can include the same dependency in their own
WEB-INF\lib to maintain this isolation.
For dependency utility libraries that must be shared between EJB and Web applications, those libraries need to be loaded at the EAR classloader. It turns out that any library specified in the manifest
Class-Path: entry of an EJB will be loaded by an EAR classloader to give the right visibility to those classes. This allows an EJB developer to package any common exception classes and custom input parameter classes that are visible to a Web application and the EJB into a
common.jar file that is placed in the manifest
Class-Path:. In addition to the public interfaces and stub implementation classes, the
common.jar file will also be loaded at the EAR level, allowing a Web application to have visibility to all of the classes used by the EJB.
The EJB 2.0 Public Final Draft 2 introduced the concept of local interfaces and put an interesting twist into the EAR classloading problem. With local interfaces, co-located clients and EJBs can be accessed using pass-by-reference semantics instead of pass-by-value semantics. In order for a client of an EJB to do pass-by-reference invocations, having visibility to the public interfaces and stub implementation classes of an EJB will not work. In fact, the client of an EJB needs to have a direct reference to the implementation classes of the EJB's container. Because of local interfaces, clients of EJBs need to be able to load much more than they needed to previously. Because of this restriction, the classloading scheme detailed above will not work. The solution to this problem is to make classloaders of any applications that may need to use EJB children of the EJB classloader.
Please refer to Figure 2: Complex Classloading Approach for a graphical representation of a complex classloading scheme that a vendor could implement. In this model, Web application classloaders are children of the EJB classloader. This allows all Web applications to have visibility to all of the files they need in order to behave as clients of the EJBs. Each Web application is still loaded in a custom classloader to achieve isolation, though. In this implementation, the EJB classloader does not need to export any files to the EAR classloader, making the overall structure simpler to understand.
There is an ambiguity in the J2EE specification that has been exposed by certain implementations seen to date. The J2EE specification is ambiguous as to how dependency libraries specified in the manifest
Class-Path: of a Web application should be loaded. It is very clear that a utility library specified by
WEB-INF\lib should only be loaded by the classloader of the Web application and remains isolated. However, if a utility library is specified in the manifest
Class-Path: of the Web application, it is not stated as to whether the library should be loaded by the Web application's classloader or exported to the EAR classloader. This can have a behavioral impact. If it is known that a utility library will only be loaded once for all Web applications, the Web applications can take advantage of knowing that a singleton class will only create a single object that can be shared among all Web applications. However, if the utility library were isolated by each Web application classloader, a singleton class would create a single object in each Web application.
Currently, Silverstream's application server and the J2EE reference implementation load utility libraries specified in the manifest
Class-Path: of a Web application at the EAR classloader level. WebLogic Server 6.1 Beta loads these libraries as part of the Web application classloader. It appears, though, that it is likely that WebLogic Server 6.1 GA will modify this approach to support loading Web application utility libraries at the EAR level. (This actually makes sense, since you can always get Web application isolation by placing utility libraries in the
It is important to note that for both of the scenarios described in this architecture, if two Web applications want to use two different versions of the same EJB (the different versions have slightly modified class files), this can only be achieved by doing two separate EAR applications. Since all EJBs are effectively loaded at the EAR level, only one version of a class specified in an EJB can be loaded by the EAR application at any given time.
Given the discussion in this article, I recommend that, when designing an application that uses JSPs, servlets, and EJBs together, any class that is shared by more than one application be placed into a
common.jar file that is specified in the manifest
Class-Path: entry of all applications that make use of it. Additionally, add any other support libraries to the appropriate manifest
Class-Path: and place any Web application-specific libraries in the
WEB-INF\lib. Following this approach, you should have smooth sailing from here on out!
Tyler Jewell , Director, Technical Evangelism, BEA Systems Tyler oversees BEA's technology evangelism efforts that are focused on driving early adoption of strategic BEA technologies into the ISV and developer community.
Read more EJB 2 columns.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.