This section will show you how to run JBoss AOP with standalone applications and how to run it integrated with the JBoss application server.
There are 3 different modes to run your aspectized applications. Precompiled, loadtime or hotswap. JBoss AOP needs to weave your aspects into the classes which they aspectize. You can choose to use JBoss AOP's precompiler to accomplish this (Compiletime) or have this weavining happen at runtime either when the class is loaded (Loadtime) or after it (HotSwap).
Compiletime happens before you run your application. Compiletime weaving is done by using the JBoss AOP precompiler to weave in your aspects to existing .class files. The way it works is that you run the JBoss AOP precompiler on a set of .class files and those files will be modified based on what aspects you have defined. Compiletime weaving isn't always the best choice though. JSPs are a good instance where compiletime weaving may not be feasible. It is also perfectly reasonable to mix and match compile time and load time though. If you have load-time transformation enabled, precompiled aspects are not transformed when they are loaded and ignored by the classloader transformer.
Loadtime weaving offers the ultimate flexibility. JBoss AOP does not require a special classloader to do loadtime weaving, but there are some issues that you need to think about. JDK5 actually has a simple standard mechanism of hooking in a class transformer through the -javaagent. JBoss AOP an additional load-time transformer that can hook into classloading via this standard mechanism.
Load-time weaving also has other serious side effects that you need to be aware of. JBoss AOP needs to do the same kinds of things that any standard Java profiling product needs to do. It needs to be able to process bytecode at runtime. This means that boot can end up being significantly slowed down because JBoss AOP has to do a lot of work before a class can be loaded. Once all classes are loaded though, load-time weaving has zero effect on the speed of your application. Besides boottime, load-time weaving has to create a lot of Javassist datastructure that represent the bytecode of a particular class. These datastructures consume a lot of memory. JBoss AOP does its best to flush and garbage collect these datastructures, but some must be kept in memory. We'll talk more about this later.
HotSwap weaving is a good choice if you need to enable aspects in runtime and don't want that the flow control of your classes be changed before that. When using this mode, your classes are instrumented a minimum necessary before getting loaded, without affecting the flow control. If any joinpoint becomes intercepted in runtime due to a dynamic AOP operation, the affected classes are weaved, so that the added interceptors and aspects can be invoked. As the previous mode, hot swap contains some drawbacks that need to be considered.
JBoss AOP does not require an application server to be used. Applications running JBoss AOP can be run standalone outside of an application server in any standard Java application. This section focuses on how to run JBoss AOP applications that don't run in the JBoss application server.
Running a precompiled aop application is quite similar to running a normal java application. In addition to the classpath required for your application you need to specify the files required for aop:
As an alternative, you can replace all those jars by jboss-aop-jdk50-single.jar, that bundles the libraries used by JBoss AOP with JBoss AOP class files in a single jar.
JBoss AOP finds XML configuration files in these two ways:
If you are using annotated bindings (See Chapter "Annotated Bindings"), you must tell JBoss AOP which JARS or directories that may have annotated @Aspects. To do this you must set the jboss.aop.class.path system property. (You can specify multiple jars or directories separated by ':' (*nix) or ';' (Windows), i.e. -Djboss.aop.class.path=aspects.jar;classes)
So to run a precompiled AOP application, where your jboss-aop.xml file is not part of a jar, you enter this at a command prompt:
$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \ -Djboss.aop.class.path=aspects.jar com.blah.MyMainClass
To run a precompiled AOP application, where your application contains a jar with a META-INF/jboss-aop.xml file, you would need to do this from the command-line:
$ java -cp=<classpath as described above> com.blah.MyMainClass
In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files. The usage:
$ run-precompiled15 classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \ com.blah.MyMainClass [args...]
If your application is not in a jar with a META-INF/jboss-aop.xml file, you must specify the path to your *-aop.xml files in the -aoppath parameter, and if your class comtains aspects configured via annotations ( @Aspect etc.) you must pass in this classpath via the -aopclasspath parameter.
This section describes how to use loadtime instrumentation of classes with aop. The classes themselves are just compiled using Java, but are not precompiled with the aop precompiler. In the examples given if your classes are contained in a jar with a META-INF/jboss-aop.xml file, you would omit the -Djboss.aop.path system property.
JDK 5.0 has a pluggable way of defining a class transformer via the java.lang.instrument package. JBoss AOP uses this mechanism to weave aspects at class load time with JDK 5. Using loadtime with JDK 5 is really easy. All you have to do is define an additional standard switch on the Java command line. -javaagent:jboss-aop-jdk50.jar. For these examples make sure that you use jboss-aop-jdk50.jar and not jboss-aop.jar in your classpath. Here's how run an AOP application in JDK 5.0 with loadtime instrumentation, where your jboss-aop.xml file is not part of a jar:
$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \ -javaagent:jboss-aop-jdk50.jar com.blah.MyMainClass
And to run an AOP application in JDK 5.0 with loadtime instrumentation, where your application contains a jar with a META-INF/jboss-aop.xml file:
$ java -cp=<classpath as described above> -javaagent:jboss-aop-jdk50.jar \ com.blah.MyMainClass
In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files. The usage for JDK 5 is:
$ run-load15 classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \ com.blah.MyMainClass [args...]
The parameters have the same meaning as for the run-precompiled scripts.
If you invoke the previous java examples with ant, by using the ant java task, make sure that you set fork="true" in the ant java task. Failure to do so, causes the java task to execute in the same VM as ant which is already running. This means that the special classloader used to do the loadtime transformations does not replace the standard one, so no instrumentation takes place.
Boss AOP needs to do the same kinds of things that any standard Java profiling product needs to do. It needs to be able to process bytecode at runtime before a class is loaded. JBoss AOP has to do a lot of work before a class can be loaded. This means that boot time can end up being significantly slowed down. Once all classes are loaded though, load-time weaving has zero effect on the speed of your application.
Besides boottime, load-time weaving has to create a lot of Javassist datastructures that represent the bytecode of a particular class. These datastructures consume a lot of memory. JBoss AOP does its best to flush and garbage collect these datastructures, but some must be kept in memory. This section focuses on how you can improve the performance of Loadtime weaving.
In Java, when your application is getting close to eating up all of its memory/heapspace, the Java Garbage Collector starts to run more frequently and aggressively. When the GC starts running more often the performance of your application will suffer. JBoss AOP does its best to balance bootup speed vs. memory consumption, but it does require loading bytecode into Javassist datastructures so it can analyze and transform a class. For speed purposes, the datastructures are cached thus leading to the extra memory consumption. Javassist structures of non-transformed classes are placed a SoftReference cache, so they are GC'd when memory is running low. Transformed classes, however, are locked in the cache. Transformed classes are help in memory, as they may effect pointcut matching on classes that haven't been loaded yet.
To increase your Heap size, use the standard -Xmx switch.
Filtering probably has the greatest effect on overall boot-time speed. If you've ever worked with a Java profiling product before, you probably noticed that it has an option to filter classes that you are not interested in profiling. This can speed up performance of the tool. JBoss AOP has to analyze every class in the system to make sure it does not need to be transformed. THis is one reason why load-time weaving can be so slow. You can give JBoss AOP a lot of help by specifying sets of classes that do not need to be transformed.
To enable filtering, you can use the jboss.aop.exclude System Property. This System Property is a comma delimited list. The strings in the list can be package names and/or classnames. Packages/classes within this list will ignored by JBoss AOP. You can use the wildcard * in place of a classname, this will then exclude all classes. No other wildcards are supported.
java -Djboss.aop.exclude=org.jboss,org.apache ...
There is also a mirror opposite of exclude. The System Property jboss.aop.include overrides any thing specified with exclude.
To improve the startup time of JBoss AOP all invisible annotations (invisible annotations are all annotations that are not annotated with @Retention(RetentionPolicy.RUNTIME)) are ignored by default. To include them use the system property jboss.aop.invisible.annotations to add packages that will be included, or add "*" to include all.
java -Djboss.aop.include.annotations=com.foo.bar,org.my.company
To include all:
java -Djboss.aop.include.annotations=*
To increase overall runtime performance, JBoss AOP has to dynamically create a lot of extra code. If you turn off these optimizations, JBoss AOP can weave a bit quicker. There is a good chance, depending on your application that you will not even notice that these optimizations are turned off. The jboss.aop.optimized system property can be set to turn off optimizations.
java -Djboss.aop.optimized=false ...
JBoss AOP tries to aggressive prune cached Javassist structures. This may, may not have a tiny effect on performance. The jboss.aop.prune system property can be set to turn off pruning.
java -Djboss.aop.prune=false ...
Strangely enough, it seems that the -client VM switch is a little faster for JBoss AOP loadtime weaving that -server. If you are using the -server VM, trying switching to -client (the default).
It is significantly slower to use the -javaagent vs. the bootclasspath approach.
A way to completely ignore classes from being instrumented. This overrides whatever you have set up using the include/exclude filters. The system property is jboss.aop.ignore, and you can use wildcards in the classnames. As for include/exclude you may specify a comma separated list of class name patterns. This following example avoids instrumenting the cglib generated proxies for hibernate:
java -Djboss.aop.ignore=*$$EnhancerByCGLIB$$*
The HotSwap feature allows bytecode of your classes to be weaved in runtime. This results in application flow control changes to your classes only when joinpoints become intercepted (to do this, use the dynamic aop funcionality provided by JBoss AOP). This is a mode to be considered when you want to assure the flow control of your classes will be kept intact until a binding or a interceptor is added.
This mode is currently provided through the java.lang.instrument.Instrumentation hot swap functionality, which is part of the JVMTI (Java Virtual Machine Tool Interface) added in JDK5. So, you cannot run JBoss AOP in this mode when using a previous JDK version.
To enable HotSwap, you have to add an argument to the Java command line in a very similar way to the "Loadtime with JDK5" mode: -javaagent:jboss-aop-jdk50.jar=-hotSwap. The difference is that the -hotSwap argument was added to the agent parameter list.
This way, if your jboss-aop.xml file is contained in a jar file, run:
$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \ -javaagent:jboss-aop-jdk50.jar=-hotSwap com.blah.MyMainClass
And if your jboss-aop.xml file is contained in a jar, run the following command line:
$ java -cp=<classpath as described above> -javaagent:jboss-aop-jdk50.jar=-hotSwap \ com.blah.MyMainClass
The run-load15HotSwap batch/script files contained in the /bin folder of the distribution are similar to the run-load15 ones, described in the previous subsection. All aop libs are included in these script files. To use them, run:
$ run-load15 classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \ com.blah.MyMainClass [args...]
When hotswap is enabled, the prunning of classes is turned off. Therefore, if you try to configure the jboss.aop.prune option as true, this setup will be ignored.
As with the "Loadtime with JDK5" mode, the HotSwap mode results in a boot time delay. Besides this drawback, the execution of some dynamic aop operations may be slower than in the other modes, when classes need to be hot swapped. The available options to tune performance are the same as described in the "Improving Loadtime Performance" subsection, except the pruning of classes.
JBoss AOP is integrated with JBoss 4.0.1+ application server. The integration steps are different depending on what version of JBoss AS you are using and what JDK version you are using. It is also dependent on whether you want to use loadtime or compiletime instrumentation.
If you wish to use JBoss AS 4.0.0 you will need to use JBoss AOP 1.0 Final since later releases of JBoss AOP leverage improvements in JBoss's deployement architecture. If you do this please consult the docs for JBoss AOP 1.0 Final. It is recommended though that you use the latest versions of JBoss AOP and AS.
Based on what JDK you are on and what loadtime weaving option you want to you, you must configure JBoss AS differently.
To deploy an AOP application in JBoss you need to package it. AOP is packaged similarly to SARs(MBeans). You can either deploy an XML file directly in the deploy/ directory with the signature *-aop.xml along with your package (this is how the base-aop.xml, included in the jboss-aop.deployer file works) or you can include it in the jar file containing your classes. If you include your xml file in your jar, it must have the file extension .aop and a jboss-aop.xml file must be contained in a META-INF directory, i.e. META-INF/jboss-aop.xml.
If you want to create anything more than a non-trivial example, using the .aop jar files, you can make any top-level deployment contain a .aop file containing the xml binding configuration. That is you can have a .aop file in an .ear file, or a .aop file in a war file etc. The bindings specified in the META-INF/jboss-aop.xml file contained in the .aop file will affect all the classes in the whole war!
To pick up a .aop file in an .ear file, it must be listed in the .ear/META-INF/application.xml as a java module, e.g.:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE application PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN' 'http://java.sun.com/j2ee/dtds/application_1_2.dtd'> <application> <display-name>AOP in JBoss example</display-name> <module> <java>example.aop</java> </module> <module> <ejb>aopexampleejb.jar</ejb> </module> <module> <web> <web-uri>aopexample.war</web-uri> <context-root>/aopexample</context-root> </web> </module> </application>
Note that in newer versions of JBoss (>= 4.0.5), the contents of the .ear file are deployed in the order they are listed in the application.xml. When using loadtime weaving the bindings listed in the example.aop file must be deployed before the classes being advised are deployed, so that the bindings exist in the system before the ejb, servlet etc. classes are loaded. This is acheived by listing the .aop file at the start of the application.xml. Older versions of JBoss did not have this issue since the contained .aop files were deployed before anything else, and this still holds true for other types of archives such as .sar and .war files.
JBoss AS has special integration with JDK 5.0 to do loadtime transformations. This section explains how to use it.
JBoss AOP comes distributed with the JBoss 4.x Application Server. The version that comes with JBoss 4.x does not take advantage of JDK 5.0 features. It is best to install the jboss-aop-jdk50.deployer/ distribution into your JBoss Application Server install base. See the "Installing" chapter for more details.
If you want to do load-time transformations with JBoss 4 and JDK 5, there are two steps you must take.
The jboss-aop-jdk50.deployer file contains some MBeans that deploy and manage the AOP framework.
<mbean code="org.jboss.aop.deployment.AspectManagerServiceJDK5" name="jboss.aop:service=AspectManager"> <attribute name="EnableLoadtimeWeaving">true</attribute> <!-- only relevant when EnableLoadtimeWeaving is true --> <attribute name="SuppressTransformationErrors">true</attribute> <attribute name="Prune">true</attribute> <attribute name="Include">org.jboss.test</attribute> <attribute name="Exclude">org.jboss.</attribute> <attribute name="Optimized">true</attribute> <attribute name="Verbose">false</attribute> </mbean> <mbean code="org.jboss.aop.deployment.AspectDeployer" name="jboss.aop:service=AspectDeployer"> </mbean>
By default, JBoss application server will not do load-time bytecode manipulation of AOP files. You can turn load-time on by setting the EnableLoadtimeWeaving attribute to true. If SuppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because sometimes a JBoss deployment will not have all the classes a class references.
The next step is to copy the pluggable-instrumentor.jar from the lib-50/ directory of your JBoss AOP distribution to the bin/ directory of your JBoss AOP application server installation. Next edit run.sh or run.bat (depending on what OS you're on) and add the following to the JAVA_OPTS environment variable
set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME% -javaagent:pluggable-instrumentor.jar
After modifying JAVA_OPTS and setting the EnableLoadtimeWeaving to true, then you should be ready to go.
Note that the code attribute of the AspectManager mbean must be org.jboss.aop.deployment.AspectManagerServiceJDK5 as that is what works with the -javaagent weaver.
If you are using JRockit 5.0 and you wish to use the JDK 5 features of JBoss AOP, you should replace jboss-aop.deployer with jboss-aop-jdk50.deployer as mentioned in "JBoss 4.x and JDK 5.0".
If you want to do load-time transformations with JBoss 4 and JRockit, there are two steps you must take.
The jboss-aop.deployer or jboss-aop-jdk50.deployer file (depending on which you are using) contains some MBeans that deploy and manage the AOP framework.
<mbean code="org.jboss.aop.deployment.AspectManagerService" name="jboss.aop:service=AspectManager"> <attribute name="EnableLoadtimeWeaving">true</attribute> <!-- only relevant when EnableLoadtimeWeaving is true --> <attribute name="SuppressTransformationErrors">true</attribute> <attribute name="Prune">true</attribute> <attribute name="Include">org.jboss.test</attribute> <attribute name="Exclude">org.jboss.</attribute> <attribute name="Optimized">true</attribute> <attribute name="Verbose">false</attribute> </mbean> <mbean code="org.jboss.aop.deployment.AspectDeployer" name="jboss.aop:service=AspectDeployer"> </mbean>
By default, JBoss application server will not do load-time bytecode manipulation of AOP files. You can turn load-time on by setting the EnableLoadtimeWeaving attribute to true. If SuppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because sometimes a JBoss deployment will not have all the classes a class references.
The next step is to copy the jrockit-pluggable-instrumentor.jar from the lib-50/ directory of your JBoss AOP distribution to the bin/ directory of your JBoss AOP application server installation. Next edit run.sh or run.bat (depending on what OS you're on) and add the following to the JAVA_OPTS and JBOSS_CLASSPATH environment variables
# Setup JBoss sepecific properties JAVA_OPTS="$JAVA_OPTS -Dprogram.name=$PROGNAME \ -Xmanagement:class=org.jboss.aop.hook.JRockitPluggableClassPreProcessor" JBOSS_CLASSPATH="$JBOSS_CLASSPATH:jrockit-pluggable-instrumentor.jar"
After modifying JAVA_OPTS, JBOSS_CLASSPATH and setting the EnableLoadtimeWeaving to true, then you should be ready to go.
Note that the code attribute of the AspectManager mbean must be org.jboss.aop.deployment.AspectManagerService as that is what works with the JRockit special hooks.
The same rules apply to JBoss AS for tuning loadtime weaving performance as standalone Java. See the previous chapter on tips and hints. YOU CANNOT USE THE SAME SYSTEM PROPERTIES THOUGH! Switches like pruning, optimized, and include/exclude are configured through the jboss-aop.deployer/META-INF/jboss-service.xml file talked about earlier in this chapter. You should be able to figure out how to turn the switches on/off from the above documentation.
By default all deployments in JBoss are global to the whole application server. That means that any ear, sar, jar etc. that is put in the deploy directory can see the classes from any other deployed archive. Similarly, aop bindings are global to the whole virtual machine. This "global" visibility can be turned off per top-level deployment.
How the following works may be changed in future versions of jboss-aop. If you deploy a .aop file as part of a scoped archive, the bindings etc. applied within the .aop/META-INF/jboss-aop.xml file will only apply to the classes within the scoped archive and not to anything else in the application server. Another alternative is to deploy -aop.xml files as part of a service archive (SAR). Again if the SAR is scoped, the bindings contained in the -aop.xml files will only apply to the contents of the SAR file. It is not currently possible to deploy a standalone -aop.xml file and have that attach to a scoped deployment. Standalone -aop.xml files will apply to classes in the whole application server.
If you have an application using classloader isolation, as long as you have "prepared your classes" you can later attach a .aop file to that deployment. If we have a .ear file scoped using a jboss-app.xml file, with the scoped loader repository jboss.test:service=scoped:
<jboss-app> <loader-repository> jboss.test:service=scoped </loader-repository> </jboss-app>
We can later deploy a .aop file containing aspects and configuration to attach that deployment to the scoped .ear. This is done using the loader-repository tag in the .aop files META-INF/jboss-aop.xml file.
<?xml version="1.0" encoding="UTF-8"?> <aop> <loader-repository>jboss.test:service=scoped</loader-repository> <!-- Aspects and bindings --> </aop>
This has the same effect as deploying the .aop file as part of the .ear as we saw previously, but allows you to hot deploy aspects into your scoped application.