Deployment Considerations
In this section, we consider some of the implications of deploying applications to a single-server development environment, as well as the changes to your deployment strategy when migrating to a multiserver domain or clustered domain. We examine how you can partially redeploy files within web applications and EJB modules, and also examine class visibility restrictions on resource adapters. In addition, we cover how to effectively package shared utility classes within an enterprise application. Finally, we look at how to register server-specific startup and shutdown classes, and how to register application-specific listener classes that respond to specific events during the deployment life cycle of the application.
12.5.1 Single-Server Deployment
Suppose your domain consists of a single WebLogic server a setup that is typical during the development stages of your application. This means that you're deploying applications directly to the Administration Server itself for development purposes. This setup is ideal for iterative development environments, where your IDE in combination with build scripts can deploy to WebLogic Server as you develop your applications.
Setting up this scenario is quite simple you need to create a WebLogic domain that consists of the Administration Server alone. As we saw earlier, this single-server setup automatically defaults to the development mode. This means you can immediately begin deploying your application components by placing them under the applications folder of your domain. Things are even simpler if you deploy application components in exploded format. Because the Administration Server starts up in no-staging mode by default, this allows you to make in-place updates to static files and JSPs within any exploded WAR. Likewise, you can update servlets in place by simply overwriting the older class files in the WEB-INF/classes directory of your exploded application. In fact, as we shall see later, you can perform in-place updates on any class that's loaded by the web container! This includes the tag-implementation classes for any JSP tags you may use.
In many instances you will need to redeploy an application. For example, when you add a new servlet to a WAR deployed in exploded format, even though the new class files have been copied to WEB-INF/classes, your changes to the web.xml descriptor file will not be picked up by WebLogic until you redeploy the WAR. Of course, you can redeploy the web application using either the Administration Console or the Deployer tool. Alternatively, you could trigger the redeployment of the exploded WAR by "touching" a REDEPLOY file placed under the WEB-INF directory.
Likewise, if you need to incorporate any changes made to EJBs deployed directly under the applications directory, you need to simply "touch" the REDEPLOY file located under the META-INF directory, in which case the EJB module or resource adapter is redeployed. If the EJBs and resource adapters are packaged within an exploded EAR, you must redeploy the entire EAR. Again, this can be done by simply touching a REDEPLOY file placed under the META-INF folder of the exploded EAR. It is a harsh world to have to redeploy the entire EAR in order to refresh the EJBs within the exploded EAR. But, as we've already seen, the reason for enforcing this constraint lies within WebLogic's classloading hierarchy.
12.5.2 Multiserver Deployment
If your development environment spans beyond a single WebLogic instance, the auto-deployment features are ineffectual because the auto-deploy feature supports deployment only to the Administration Server. In these situations, you should consider using the Deployer tool, which lets you target applications to particular servers within the domain. Alternatively, you can use the Administration Console to handle multiserver deployments. We already have seen how the Deployer tool lets you deploy, redeploy, and undeploy an application across multiple target servers. Typically, you need to redeploy static files or JSPs within a web application:
java weblogic.Deployer -name mywebapp -targets server1,server2 -redeploy help/*.jsp
Or you need to refresh EJB modules used by your web applications:
java weblogic.Deployer -name myEJB -targets server1,server2 -redeploy
Alternatively, you could rely on external staging for your application. In this case, if you need to redeploy the application on multiple servers, you need to manually copy the application to the staging directory of each target server. Then you need to use the Deployer tool along with its -external_stage option to activate your application on all target servers. Clearly, it becomes easier to distribute the application files if the Administration Server and the managed servers use a shared disk.
12.5.3 Cluster Deployment
You should be careful when deploying applications to a WebLogic cluster. By default, WebLogic allows you to deploy applications to a partial cluster.[2] In other words, the two-phase deployment strategy ensures that the deployment succeeds on those clustered servers that can be reached by the Administration Server at the time of deployment. If it detects an unavailable clustered server during the prepare phase, a warning message is written to the console log, and the deployment proceeds on all available members of the cluster. Deployment on the unavailable server is initiated the next time the server starts and joins the cluster.
[2] In WebLogic 7.0, deployment to a partial cluster is available only once you've applied Service Pack 1 or higher.
Alternatively, you can configure the domain so that the two-phase deployment strategy succeeds only if all members of the cluster are reachable when deploying an application to a WebLogic cluster. If a clustered server instance is not available during the prepare phase, the deployment is terminated with an error message written to the console log. You can either start the failed server or remove it from the cluster, before reinitiating the deployment. In order to configure this strict deployment strategy, you can select the domain from the left pane of the Administration Console, and then navigate to the Configuration/General tab. By enabling the Enable Cluster Constraints option, you ensure that an application is deployed to a cluster only if all members of the cluster also are available at the time of deployment. Another way to enforce the same constraint is to enable the -DClusterConstraintsEnabled=true command-line option when starting up the Administration Server.[3] We recommend you ensure that all servers in the cluster are running and available before you deploy applications to the cluster. You should not modify a cluster's membership during deployment i.e., add, remove, or shut down managed servers when one or more deployment tasks on the cluster are in progress.
[3] In WebLogic 7.0, you can enforce this strict deployment strategy by invoking the Deployer tool with the -enforceClusterConstraints flag.
WebLogic also allows you to deploy a pinned service to multiple managed servers in a cluster.[4] However, this approach isn't recommended because it affects the load balancing and scalability of your solution. If you target a pinned service to multiple servers within a cluster, a warning message is written to the logs, but the deployment still succeeds.
[4] WebLogic 7.0 prevents you from deploying a pinned service to multiple servers in the cluster, unless you have applied Service Pack 1 or higher.
Remember, if you shut down the Administration Server for a domain, you cancel all pending deployments. This means you could potentially end up with an inconsistent deployment across the cluster. For instance, you could deploy an application to a partial cluster where one or more of the clustered servers are unavailable, then shut down the Administration Server and later restart the unavailable server in the cluster. Because the Administration Server is unavailable, the target server is incapable of receiving the pending deployment task for that particular application. In this way, your cluster reaches a state where the application is not available on all members of the cluster. Of course, this inconsistent state will remain only until the Administration Server is brought back up. Thus, the availability of the Administration Server is vital to ensuring homogenous deployments across the cluster.
12.5.4 Web Applications
Let's revisit some of the issues concerning deploying web applications to WebLogic. As mentioned earlier, you can run WebLogic in two modes:
- In development mode, where the auto-deployment feature is enabled
- In production mode, where the WebLogic instance participates in a live deployment
Each mode has a very different impact on how web applications are deployed.
12.5.4.1 Using auto-deployment
You'll find that auto-deployment works differently, depending on whether the web application is deployed as a WAR (in archived format) or as a directory (in exploded format). If the web application has been deployed in archived format, you can trigger redeployment automatically, simply by modifying the WAR file or by overwriting it with a new version. If the web application is targeted to other managed servers, it also will be redeployed on those server instances.
If the web application has been deployed in exploded format, many of the changes to the resources within the web application are reflected automatically, without the need for redeployment. For instance, changes to static files (HTML pages, images, etc.) and JSP pages are reflected automatically. You also can refresh compiled Java classes used by the web application. More accurately, we mean Java classes loaded by the web application classloader. This means you can overwrite compiled classes for the servlets, JSP tag implementation classes, and any Java classes located under the WEB-INF/classes folder without the need for redeployment. You even can copy new classes into the WEB-INF/classes folder, and they will be loaded automatically by the web container on demand. Of course, if you've created new servlets or JSP tags, you will need to register those changes in the appropriate descriptors and redeploy the web application. The only annoying side effect of this hot-deploy feature is that by replacing any Java class with a later timestamp, you force the web container to reload everything under the WEB-INF/classes folder using a new classloader.
As we saw earlier, you can trigger the redeployment for the web application by simply touching a REDEPLOY file in the WEB-INF directory. Alternatively, you can use the Administration Console. Select the web application from the left pane and then click the Redeploy button. You also can adjust the frequency with which WebLogic looks at the filesystem for changes. Simply navigate to the Deployments/Web Application Modules node in the left pane of the Administration Console, select the desired web application, and then go to the right pane to change the value of the Servlet Reload Check Secs setting in the Configuration/Descriptor tab.
12.5.4.2 Using production mode
If the web application has been deployed as a WAR, you need to redeploy the entire WAR to reflect any changes to JSP pages, static files, or compiled Java classes. However, if the web application has been deployed as an exploded directory, you can use the Deployer tool to reflect any changes you've made to JSPs or static files:
java weblogic.Deployer -name myapp -redeploy mywar/index.jsp
So, WebLogic permits partial redeployment only for web applications that are deployed in an exploded form. If you've overwritten or created new Java classes, or modified the XML descriptors for the web application, you must redeploy the entire web application for those changes to take effect.
You also need to be aware of serious consequences when redeploying a web application on a production WebLogic environment. If a web application has been deployed using the default staging mode, the entire web application may need to be distributed over the network to all the targeted servers. This increased administration traffic may have performance implications on your network.
By default, WebLogic destroys all current HTTP user sessions when you redeploy a web application. You could work around this limitation by initiating the redeployment when no one is using your web application. Alternatively, you could instruct WebLogic to preserve all active user sessions when the web application is redeployed. To preserve user sessions across redeployment, you must enable the save-sessions-enabled flag in the container-descriptor element of the weblogic.xml descriptor file for the web application:
save-sessions-enabled true
12.5.5 EJB Modules
WebLogic 8.1 lets you organize the application's classloaders in a way that lets you reload individual EJB modules. By assigning a separate classloader to each EJB module, you can ensure that an EJB module may be redeployed independently of others. The following portion from the weblogic-application.xml descriptor file shows how to set up this classloading scheme:
EJB1.jar EJB2.jar
In addition, WebLogic lets you reload the EJB implementation classes, without having to reload the entire EJB module. We recommend that you utilize this EJB reload feature only in a development setting. Because EJBs are accessed via their interfaces, WebLogic is able to load the EJB implementation classes in their own classloaders, thereby allowing you to reload these classes without having to redeploy the entire module. The following example shows how to partially update the files within an application:
java weblogic.Deployer -name myapp -redeploy myejb/FooImpl.class yourejb
After the -redeploy option, you must specify a list of files that need to be refreshed. The paths must be relative to the root of the application, and must refer to either a specific element (e.g., FooImpl.class) or a module within the application (e.g., yourejb). This approach is similar to how you would partially update individual JSP pages within a web application.
If you have specified the EJB implementation class, WebLogic is able to refresh the class without having to redeploy the EJB module. However, if you've specified an EJB interface or an EJB module, the whole EJB module must be redeployed. Depending on the classloader hierarchy, this may result in other modules being redeployed as well. For instance, if the modules myejb and yourejb are assigned the same classloader, any request to redeploy myejb also triggers a redeployment on yourejb (and vice versa). Moreover, if a module (say, mywar) is loaded into the child of the myejb classloader, any request to redeploy myejb also triggers a redeployment on mywar.
12.5.6 Utility Classes
There are several ways to make shared libraries and utility classes available to various application components. If the utility classes need to be shared by multiple applications, you can include them in WebLogic's classpath so that they can be picked up by the system classloader. This also holds true for any classes that are used by WebLogic during the startup sequence for instance, JDBC driver classes, XML parser factories, and RMI implementation classes. However, if you need to replace any of these libraries with newer versions, these changes are reflected only after you reboot the server. You should consider this approach only if you want to explicitly share the libraries across multiple deployed applications, and these libraries are not likely to change very often.
If the utility classes will be used only by a specific web application, you can either place them in the WEB-INF/classes folder, or package them into a JAR and then place the JAR in the WEB-INF/lib folder. If you update or overwrite any of these utility classes, you need only to redeploy the web application for those changes to take effect.
If the utility classes must be accessible to an EJB module, you can either bundle them directly into the EJB JAR, or use the standard Class-Path entry in the EJB's META-INF/MANIFEST.MF manifest file to reference the shared libraries:
Manifest-Version: 1.0 Class-Path: shared_library1.jar shared_libary2.jar
Because all EJB modules are loaded into the same classloader, this implies that the libraries are visible to all EJBs within the enterprise application. Furthermore, because the web application classloader is a child of the EJB classloader, this means that the shared libraries will also be visible to all web applications. In this way, you can make the shared libraries accessible to all EJB modules and web applications within the enterprise application.
A downside of using the manifest file to extend the EJB classloader is that you must create an EJB JAR or web application WAR. Hence, shared libraries referenced from within the manifest file have no effect in exploded applications.
WebLogic 8.1 provides a less portable but simpler approach to sharing libraries and utility classes between the modules of an enterprise application. Simply place the utility classes in the APP-INF/classes folder and the libraries in the APP-INF/lib folder of your enterprise application. The following example illustrates the internal structure of an EAR that allows you to make utility libraries accessible to all modules within the EAR:
APP-INFliblog4j.jar APP-INFlibdom4j.jar APP-INFlibjdbc-ra_tx.jar ... APP-INFclassescomoreillywlguideutilsMyUtils.class ... META-INFapplication.xml META-INFweblogic-application.xml ejb_jar1.jar ejb_jar2.jar ... my_webapp1.war my_webapp2.war ...
One advantage of this approach is that it will work with exploded applications as well. All of the utility libraries that are deployed in this way are loaded by the application classloader, and hence can be shared by all modules.
In addition, classes placed under the application's APP-INF folder are accessible to all EJBs and web applications, regardless of the classloader hierarchy you specify. Any module-specific classloader is a descendant of the base application classloader. On the other hand, the visibility of any libraries declared in the EJB JAR's manifest file is limited only by the scope of its classloader and any of its child classloaders. So, under the default classloading scheme, classes referenced in the EJB JAR's manifest file are available to all EJBs and web applications. If you have defined a custom classloader hierarchy for the enterprise application, the libraries referenced in the EJB JAR's manifest file are accessible either to the EJB module itself or to other modules as well, depending on how you have set up the classloader hierarchy.
By sharing the same copy of utility classes and library JARs, you maintain consistency among the various applications and their modules, and also ease the task of managing the overall deployment.
12.5.7 Resource Adapters
In WebLogic 8.1, a resource adapter packaged within an enterprise application is assigned its own classloader. This means that the other web applications and EJB modules within the application cannot access the classes implementing the resource adapter. To make the resource adapter implementation classes visible to EJB modules and web applications, you should treat them as utility classes and libraries. In other words, you can either place the resource adapter classes in the APP-INF/classes folder, or package them in a JAR and then place the JAR in the APP-INF/lib folder. Also ensure that you don't include any resource adapter classes in WebLogic's system classpath.
12.5.8 Startup and Shutdown Classes
Startup and shutdown classes provide you with the opportunity to execute Java code during the server's startup or shutdown sequence. A startup class is any Java class that implements the weblogic.common.T3StartupDef interface. Similarly, a shutdown class is any Java class that implements the weblogic.common.T3ShutdownDef interface. Example 4-6 shows how to create a startup class that registers a custom RMI object. Note that startup classes are not packaged like J2EE components they are distributed simply as class files, or perhaps bundled in a JAR. To deploy a startup or shutdown class, you need to make the class available to the server's classpath. If your domain is configured to use Node Managers, you also must add it to the classpath attribute in the Remote Start tab for the Managed Server.
Once the classes are placed in the server's classpath, you can then deploy the class from the Administration Console. Navigate to the Deployments/Startup & Shutdown node from the left pane, and then choose one of the "Configure a new ..." options to set up a startup or shutdown class. You will need to supply the fully qualified class name and values for any arguments that are expected by the class. Startup classes support two additional configuration options:
"Failure is Fatal"
This option determines whether a failure in the startup class should prevent the server from starting. By default, the server proceeds with its boot sequence even if a startup class fails.
"Run before Application Deployments"
This option determines whether the startup class should be run before (or after) all services have been instantiated and all applications have been deployed. By default, startup classes are run after applications are deployed, at which stage all the services, including JMS and JDBC, are also in place.
The ServerMBean interface provides an additional Run Before Application Activation attribute, which ensures the startup classes are invoked just after the services have been initialized, but before any of the applications are deployed. Figure 12-3 illustrates these stages during the server's startup sequence.
Figure 12-3. Stages during server startup sequence
12.5.9 Application Deployment Life Cycle Listeners
In WebLogic 8.1, you can associate a listener class with an enterprise application, which is invoked at specific times during the deployment life cycle of the enterprise application. This provides you with the opportunity to execute specific actions either before or after the enterprise application is deployed or undeployed. A common use for the life cycle listener class is to initialize (or destroy) singleton objects, such as an application-wide cache of EJB home objects. An application life cycle listener class must extend the weblogic.application.ApplicationLifecycleListener abstract base class. Example 12-4 shows a simple implementation of such a listener class.
Example 12-4. A simple deployment life cycle listener
package com.oreilly.wlguide.pkg; import weblogic.application.ApplicationLifecycleListener; import weblogic.application.ApplicationLifecycleEvent; public class MyAppLifecycleListener extends ApplicationLifecycleListener { public void preStart(ApplicationLifecycleEvent evt) { System.out.println(evt.getApplicationContext( ).getApplicationName( )); } public void postStart(ApplicationLifecycleEvent evt) { //initialize some app-specific cache of service objects... com.oreilly.wlguide.pkg.MyObjCache.initialize( ); } public void preStop(ApplicationLifecycleEvent evt) { } public void postStop(ApplicationLifecycleEvent evt) { } }
The ApplicationLifecycleListener class exposes four methods representing different points in the deployment life cycle of any enterprise application:
- The preStart( ) method is called at the beginning of the prepare phase of the application's deployment. For example, when you manually deploy the application, or when the application is being deployed during the server's startup sequence, the preStart( ) method is called on a registered listener just before the prepare phase starts.
- The postStart( ) method is called once the application is deployed i.e., at the end of the activation phase.
- Similarly, if you undeploy (or redeploy) an application, the preStop( ) method is called at the start of the undeployment process, and the postStop( ) method is called after the application has been undeployed.
So, for example, if you redeploy an application, the methods will be invoked on each registered application life cycle listener class in the following order: preStop( ), postStop( ), preStart( ), postStart( ). In the case of a multiserver deployment, the registered application life cycle listeners will be invoked on each server to which the enterprise application is targeted.
Once you've created the application life cycle listener class, you simply need to register it with the enterprise application. To achieve this, you can specify the listener element in the weblogic-application.xml deployment descriptor of an enterprise application. The following example shows how to register our simple listener class with an enterprise application:
com.oreilly.wlguide.pkg.MyAppLifecycleListener
The listener class must be made available to all servers that will host the enterprise application. You can either include the listener class in the server's classpath, or place it in the APP-INF/classes directory within the application itself. Alternatively, you can bundle the class into a JAR, and later package the JAR within the EAR. In this case, you also need to specify the listener-uri element to indicate the path to the JAR within the EAR file. For instance, if the sample listener class is packaged within utils.jar in the enterprise application, you must register the listener class as follows:
com.oreilly.wlguide.pkg.LifecycleListener utils.jar
Instead of registering a listener class that responds to all of these events during the application's deployment, you can create simple application-specific startup or shutdown classes. A startup class will get executed at the same point as the listener's preStart( ) method, and the shutdown class will be invoked at the same point as the listener's postStop( ) method. A startup or shutdown class extends the same abstract listener class, but simply implements a static main( ) method. Here is an example of a shutdown class:
public class MyShutdown extends ApplicationLifecycleListener { public static void main(String argp[]) { System.err.println("Just shut down the application!"); } }
Startup and shutdown classes are registered in a similar way to the listener classes, using the startup and shutdown elements in the weblogic-application.xml descriptor for the application:
com.oreilly.wlguide.pkg.MyStartup com.oreilly.wlguide.pkg.MyShutdown
You may register any number of startup and shutdown classes with an application. Startup and shutdown classes are invoked in the order in which they are declared in the weblogic-application.xml descriptor file.
We recommend that you use life cycle listeners instead of the startup and shutdown classes. The latter approach may be deprecated in future releases.