AspectWerkz supports several integration schemes. Each schemes depends on your requirements and provides different advantages and drawbacks. It is possible to use :
By default, joinpoint execution logic blocks are compiled on the fly as standalone classes.
This behavior is the default one since it provides the best performance, avoiding the use of reflection
whe it comes to executes advices and target advised method/constructor.
If you encounter troubles with this mode, it can be for now deactivated thru the option
-Daspectwerkz.jit.off=true
when you start your application (this can be used with an offline weaved
application as well).
This option might be deprecated with the 1.1 version.
Since release 1.0 AspectWerkz support to
configure several
AspectSystem
alongside the deployed applications and the container
(application server)
in which those are deployed. As described
here, you need to write an
AOP XML deployement descriptor for your aspects, that declares the
Aspects to use, and defines or refines the pointcuts (where to do) and advices (what to do), no matter your Aspects are using an annotations based
definition or a full XML defintions, or both.
aop.xml
file, you need to remember that the declared Aspects will affects the classes visible from the ClassLoader that can access this file.
For example if you package this file in
application.war/WEB-INF/aop.xml
, it will affects all web-application classes, third parties libraries from
application.war/WEB-INF/lib/
and all JSPs.
If you want to affect all JVM classes, you can use the JVM option
-Daspectwerkz.definition.file=path/aop.xml
, or better have one or more
META-INF/aop.xml
file(s)
accessible from the JVM regular classpath.
It is thus possible to organise your aspects alongside all your deployed applications, while allowing some interesting schemes: a tracing Aspect deployed
at the JVM level will affect all deployed applications, while Aspects deployed within the application itself will only affects this application.
If you plan to use
offline mode, you need to post process your application as many time as you have aop.xml files, and still packaged the aop.xml file(s)
alongside the application and/or at a JVM wide level, depending on what you want to achieve.
To summarize, you have to remember that an
META-INF/aop.xml
or
WEB-INF/aop.xml
file will affect the classes loaded by the classloader(s)
that have this aop.xml file in their path. The JVM wide aop.xml file will affect the system classloader and all child classloaders.
You should be familiar with the way Java handles ClassLoader isolation to fully understand how to deploy your own Aspects.
When you are invoking amain
method of a Class, this class is loaded (and lives) in the
System ClassLoader. All classes belonging to a path specified
with a
-cp
or
-classpath
JVM option will live in this ClassLoader.
If this class is using
java.lang.Object
and other
java.*
classes, those have been loaded (and live) in
Extension ClassLoader
or
Bootstrap ClassLoader.
The
java.lang.Object
can be seen and used by your main Class since the
System ClassLoader is by convention a
child of the
Extension ClassLoader
which is himself a
child of the
Boot ClassLoader. This relation looks like this:
Boot ClassLoader (JRE / JDK classes)
|
Extension ClassLoader (JRE extension, like SSL security etc, in jre/ext directory)
|
System ClassLoader (your main Class, and all the -cp / -classpath jars and classes)
When you are using an application server, there are usually many other classloaders. A simple view is to say that there is
one classloader per deployed application (that's why you don't need to add your war file in the JVM classpath right ?).
In fact the picture is a bit more complex to allow JSPs changes while the application is running etc.
Those
application ClassLoaders are
child of upper ClassLoaders like the
System ClassLoader, but if you deploy two war files,
they cannot share classes unless thoses classes are in an upper ClassLoader.
If we deploy to war file in a Tomcat we will end-up in the following (simplified) organization:
Boot ClassLoader (JRE / JDK classes)
|
Extension ClassLoader (JRE extension, like SSL security etc, in jre/ext directory)
|
System ClassLoader (the Tomcat main Class, and all the -cp / -classpath jars and classes)
|
Some Tomcat specific ClassLoader (does not really matters)
| |
First.war ClassLoader Second.war ClassLoader
| |
WEB-INF/lib WEB-INF/lib
and WEB-INF/classes and WEB-INF/classes
ClassLoader ClassLoader for Second.war
| | | | |
JSP ClassLoader(s) JSP ClassLoader(s)
For J2EE / EJB based application, the schemes is a bit more complex but follows the same model.
Although this kind of organization is mainly J2EE oriented, some Swing based application are using
ClassLoader parent-child relation to allow for example plugin life cycles etc.
The single idea you need to remember is that AspectWerkz deployed Aspects thru aop.xml files have the scope of the ClassLoader that has this file in its path and all its child ClassLoader(s).
Three specific paths are used:
-Daspectwerkz.definition.file=path/aop.xml
, it impacts all JVM classes (except boot classloader for convenience). Note that it is
not mandatory to name the file aop.xml
WEB-INF/aop.xml
, it will impact the classes of the web application including JSPs. It is mandatory to name the file aop.xml
META-INF/aop.xml
, it will impact the classes that can
see this file. It is mandatory to name the file aop.xml
path/META-INF/aop.xml
in the JVM classpath (
-cp path/;...
) to have the same scope as
the JVM wide defined one.
META-INF/aop.xml
file, it will aslo have the same scope.
aop.xml
file.
With this model, it is thus possible to package a tracing aspect in a jar file, with a
META-INF/aop.xml
file (with a pointcut for all public method execution f.e.)
and just add it to your classpath to allow a very simple generic tracing !
A single
aop.xml
file can declare several
Aspect Systems
for convenience. All will have the same weaving scope. The goal is mainly to
have a well organized namespace for organizing your aspects.
The
precedence will follow the order of the
<system>
elements in the XML file.
Each system must have a unique id within a ClassLoader hierarchy, as defined with
<system id="some/system">
system id
is using the application name and a path as a mnemonic, allthough it could
be any string.
<aspectwerkz> <system id="First.war/WEB-INF/FirstSystem"> <package name="examples"> <aspect class="caching.CachingAspect" deployment-model="perInstance"/> </package> </system> <system id="First.war/WEB-INF/SecondSystem"> <aspect class="examples.trace.TracingAspect" deployment-model="perJVM"/> </system> </aspectwerkz>
AspectWerkz provides several way to weave the aspects in the application classes at build time. This is called offline weaving, offline mode, or even class post-processing.
With this mode you have to be sure to post-process the application classes as many times as required if you plan to use multiple Aspect Systems as described here. There is mainly two ways to achieve this, allthough some variants can be built on top of them:-offline
option on a specific
.class
file, directory or jar file.
org.codehaus.aspectwerkz.compiler.AspectWerkzC
utility in an Ant or Maven script.
AspectWerkzC
class after all required jars have been added to the classpath.
You can find several samples of Ant and Maven integration in the AspectWerkz distribution.
The following are the options supported by the AspectWerkzC tool. Most of them can be used as well in the
AspectWerkz command line tool.
# set the classpath correctly # see bin/setEnv in the AspectWerkz distribution # Add Ant-1.5 in the classpath java -cp ... org.codehaus.aspectwerkz.compiler.AspectWerkzC [-verbose] [-haltOnError] [-verify] [-cp {additional cp i}]* {target 1} [{target i}]* # Use -Daspectwerkz.definition.file=... option to specify the XML definition file to use # Or rely on the META-INF/aop.xml and WEB-INF/aop.xml path lookup
-verbose
: turns on verbose mode (optional)
-haltOnError
: stops the compilation at the first error (target2 will not be post-processed if it fails on target1) (optional)
-verify
: do some bytecode verification (mainly usefull for AspectWerkz development team) (optional)
-cp path1;path2/some.jar
: additional classpath needed for the compilation. Put your aspect classes in this path, and your application third parties jar if any.
This is mainly needed to match on subtype patterns (java.lang.String
+), where the complete classes dependancies is needed.
For convenience you can use several
-cp ...
option. Be sure to use ";" or ":" as a path separator as for the regular JVM classpath option.
target path/classes path/application.jar
: defines the classes, classes directories and jar files to post-process. It is possible to pass as many target as needed.
<!-- =================================================== --> <!-- offline transformation of the samples --> <!-- =================================================== --> <target name="aspectwerkz:transform" depends="clean, aspectwerkz:init, aspectwerkz:compile, aspectwerkz:samples:aspectc"> <exec executable="${bin.dir}/aspectwerkz.bat"> <arg line="-offline ${basedir}/src/application/aop.xml -verbose -verify -cp ${aspect.classes} ${application.classes}"/> </exec> </target>
<target name="aspectwerkz:war:transform" depends="aspectwerkz:compile, aspectwerkz:war:aspectc"> <java classname="org.codehaus.aspectwerkz.compiler.AspectWerkzC" fork="true"> <classpath refid="project.class.path"/> <classpath> <pathelement path="${build.main.dir}"/><!-- needed for abstract Aspect activation --> <pathelement path="${build.web.dir}"/><!-- needed for Aspect activation --> </classpath> <jvmarg value="-Daspectwerkz.definition.file=${src.web.dir}/WEB-INF/aspectwerkz.xml"/> <jvmarg value="-Daspectwerkz.transform.verbose=true"/><!-- an AspectWerkz weaver option --> <arg value="-verify"/><!-- an AspectWerkzC tool option --> <arg value="-verbose"/><!-- an AspectWerkzC tool option --> <!-- below is the classes dir to post-process. It could be some jar files as well. --> <arg value="${build.web.dir}"/> <arg value="${build.main.dir}"/> </java> </target>
Once the application classes (or dir / jars) have been post-compiled, those have dependancies on
Aspect System
organization
First.war/WEB-INF/lib/
)
or added to the application regular classpath. You can use the
bin/setEnv
script of the distribution for that, or change
your application startup script to add those jars in the
-cp
or
-classpath
JVM classpath settings.
An Ant task is provided for offline weaving
First you need to activate the custom task in your Ant build.xml file with the following: (refer to Ant documentation on "taskdef" for more details)
<!-- we assume we defined a classpath with the id="aw.class.path" for AspectWerkz jars --> <path id="aw.class.path"> ... <pathelement path="pathToAspectWerkz.jar"/> ... </path> <!-- define the custom task (annotationc can be changed to what you prefer) <taskdef name="awc" classname="org.codehaus.aspectwerkz.compiler.AspectWerkzCTask" classpathref="aw.class.path"/> <!-- Note: the <daskdef> element can be nested within a <target> element at your convenience --> <!-- invoke the awc defined task --> <target name="samples:task:awc" depends="init, compile:all, samples:task:annoationc"> <awc verbose="true" definition="${basedir}/src/samples/samples-attribdef.xml" classpathref="project.class.path"> <target path="${basedir}/target/samples-classes"/> </awc> </target>
The AspectWerkzCTask task accepts the following:
Class load time weaving allows to integrate AspectWerkz seamlessly in your applications, or in your whole application server. Several schemes are supported, for Java 1.3, Java 1.4, Java 1.5, BEA JRockit JVM etc.
Allthough in some circumstances it is just a matter of adding a single JVM option and AspectWerkz jars to your classpath, a whole documentation is available here.The command line tool is the easiest way to start using AspectWerkz since it provides all classpath settings for both class load time weaving and offline post-processing.
To use it, you first need to set theASPECTWERKZ_HOME
environment variable to the directory containing the AspectWerkz installation.
set ASPECTWERKZ_HOME=C:\aop\aspectwerkz\ # export might be needed on Linux / Unix OS. # The tool assumes JAVA_HOME environment variable is correctly set.
ASPECTWERKZ_HOME/bin
directory.
You can add this directory to your
PATH
environment variable if you want.
aspectwerkz
without any arguments to print the usage message.
To post-process all class files in a specific directory (recursively), jar or zip file:
aspectwerkz -offline <definition file> [-verbose] [-verify] [-haltOnError] [-cp <classpath>]* <target classes to transform>+
-verbose
to follow each step of the processing (optional).
-verify
to verify all weaved class according to the Java Class Format specification (optional, mainly usefull for AspectWerkz development team).
-haltOnError
was set (optional).
In this case the processing stops. Else a complete status about successfull and failed targets is printed at the end of all target processing.
-cp myAspects.jar;servletAPI.jar
). It is possible to use several
-cp <classpath>
option instead of doing concatenation.
toTransform.jar /classes otherToTransform.jar
).
aspectwerkz
command)
you have to (apart from feeding it with the definition) put the aspectwerkz jars along with all
the the dependency jars the
ASPECTWERKZ_HOME/lib
directory in your classpath.
Read more about it
here.
It is possible to use the command line tool as a replacement of the
JAVA_HOME/bin/java
command. In such a case,
the command line tool will detect a suitable option for you and will enable class load time weaving.
aspectwerkz [-options] <main class> [args...]
Starting up an application using an executable jar file:
aspectwerkz [-options] -jar <jar file> [args...]
AspectWerkz
provides an RPC mechanism that allows you to use the
instrumented objects (advices and mixins) seamlessly on a remote client site.
You can use the remote proxy on the client side in two ways:
Example:
... // creates a new remote proxy for the MixinImpl class which // maps to an instance of this class on the server RemoteProxy remoteProxy = RemoteProxy.createClientProxy( new String[]{"examples.connectivity.Mixin"}, "examples.connectivity.MixinImpl", "localhost", 7777 ); // retrieves the proxy to the MixinImpl instance Mixin mixin = (Mixin)remoteProxy.getInstance(); // invoke methods on the proxy (executed on the server) System.out.println("Mixin says: " + mixin.test1()); // close the proxy (close() must always be called) remoteProxy.close(); ...
RemoteProxy
and send to the client over the wire.
The client then have access to this specific instance on the server.
Server side:
... // wrap an instance in a remote proxy on the server-side and send it to the client RemoteProxy remoteProxy = RemoteProxy.createServerProxy(anotherMixinInstance, "localhost", 7777); return remoteProxy; }
Client side:
... // retrieve the proxy to the specific instance created on the server RemoteProxy remoteProxy = mixin.getMixin(); // retrieves the proxy to the instance on the server AnotherMixin anotherMixin = (AnotherMixin)remoteProxy.getInstance(); ...
A sample have been provided and can be found in the
src/samples/examples/connectiviy
directory. Start by taking a look at the
Client.java
class.
You can run the sample by executing
ant samples:remote:server
to start up the server and then in another console execute
ant samples:remote:client
to start the client.
(When you close down the server using
^C
then the server listener
threads are still hanging so you need to close down them manually.)
The remote proxy server is a multi-threaded production-ready implementation that
is ready to serve any number of incoming requests. To configure the server settings
(number of listener threads, max/min/init size of the thread pool, backlog etc.)
you have to change the settings in the in the
aspectwerkz.properties
resource bundle and put it on the classpath. If no bundle is found default
values are used.
The server resource bundle has the following format/options:
remote.server.hostname=localhost remote.server.port=7777 remote.server.client.threads.timeout=60000 remote.server.listener.threads.nr=10 remote.server.listener.threads.backlog=200 remote.server.listener.threads.run.as.daemon=false remote.server.thread.pool.type=bounded # possible types are bounded or dynamic remote.server.thread.pool.max.size=100 remote.server.thread.pool.init.size=10 remote.server.thread.pool.min.size=10 remote.server.thread.pool.keep.alive.time=300000 remote.server.thread.pool.wait.when.blocked=true remote.server.invoker.classname=
To enable support for RPC in the
AspectWerkz
system you have to feed
the JVM with the
-Daspectwerkz.remote.server.run=true
option.
If you have specific requirements. For example if you want to handle the user
context that you (optionally) can set on the client
RemoteProxy
and have sent over or have other requirements on how you want to invoke you
objects then you can create your own implementation of the
org.codehaus.aspectwerkz.connectivity.Invoker
interface and
specify the implementation in the aspectwerkz.properties resource bundle using
the
remote.server.invoker.classname=..
option. For an example
implementation see the
org.codehaus.aspectwerkz.System.getDefaultInvoker()
method.