|
[aop]
Aspect hot deployment in practice: Implementing a JMX monitoring aspect
[
jonas
]
One of the new features in the AspectWerkz 2 architecture is the ability to deploy and undeploy aspects at runtime, e.g. to do "hot" deployment and undeployment. The implementation is based on HotSwap class redefinition and handles 'change sets' which ensures that the changes to each single join point is atomic. What this means in practice is that if you for example are deploying an aspect which has one before and one after advice, both advising the same join point (method/field etc.) then either both of them will be added or none.
The API exposed to the user is very simple and straight forward to use. Everything is handled by the
DeploymentHandle deploy(Class aspect)
DeploymentHandle deploy(Class aspect, ClassLoader deployLoader)
DeploymentHandle deploy(Class aspect, DeploymentScope scope)
DeploymentHandle deploy(Class aspect, DeploymentScope scope, ClassLoader deployLoader)
DeploymentHandle deploy(Class aspect, String xmlDef)
DeploymentHandle deploy(Class aspect, String xmlDef, ClassLoader deployLoader)
DeploymentHandle deploy(Class aspect, String xmlDef, DeploymentScope scope)
DeploymentHandle deploy(Class aspect, String xmlDef, DeploymentScope scope, ClassLoader deployLoader)
void undeploy(Class aspect)
void undeploy(Class aspect, ClassLoader loader)
void undeploy(DeploymentHandle deploymentHandle)
As you can see you can for example choose to deploy an annotation defined aspect, e.g. a regular Java5 class with AspectWerkz defined annotations (or a regular Java 1.3/1.4 class with AspectWerkz defined JavaDoc annotations, compiled with AspectWerkz's JavaDoc annotation compiler):
DeploymentHandle
(that is returned from each of these methods) here.
You also deploy a class without any annotation definition and pass in the definition in XML format. Here you pass in a string containing the Use-case: Implementing a JMX monitoring aspectNow let's take a look at a concrete example on how to hot deploy an aspect that can do some monitoring for us, report that to an JMX MBean and then undeploy it when the monitoring is done. Writing the aspectSo first, here is the (main parts of the) JMX monitoring aspect:
@Aspect
public class ResponseTimeAspect {
... // methods for registering the MBean lazily, member fields etc.
// the "invocationsToMonitor" pointcut will be defined at deployment time
// in the aop.xml file
@Around("invocationsToMonitor")
public Object monitor(StaticJoinPoint jp) throws Throwable {
Signature signature = jp.getSignature();
long tsStart = System.currentTimeMillis();
Object result = null;
try {
result = jp.proceed();
} finally {
// note: this code is using a JMX helper method and
// we will have one MBean per jointpoint signature (i.e. method, field, etc.)
long tsElapsed = System.currentTimeMillis() - tsStart;
ObjectInstance mbeanI = registerMBean(signature);
if (mbeanI != null) {
m_mbeanServer.invoke(
mbeanI.getObjectName(),
"update",
new Object[]{new Long(tsElapsed)},
new String[]{long.class.getName()}
);
}
}
return result;
}
public static void enableMonitoring(String pointcut) { ... }
public static void disableMonitoring() { ... }
}
As you can see, this aspect is defined using Java5 annotations, but if you are using Java 1.3/1.4 you can define the annnotations using JavaDoc (just put the annotation exactly as it is in the JavaDoc for the method/class) and run AnnotationC
on the class. Then the rest in this article should stay the same. You can read more about the AnnotationC
compiler here.
Hot deploy and undeploy the aspectAs you can see we have added two static methods to the aspect, these will be used to enable and disable the response time aspect. E.g. deploy it and undeploy it.
First we have the
public static void enableMonitoring(String pointcut) {
String xmlDef = "<aspect><pointcut name='invocationsToMonitor' expression='" + pointcut + "'/></aspect>";
Deployer.deploy(ResponseTimeAspect.class, xmlDef);
}
Second we have the
public static void disableMonitoring() {
Deployer.undeploy(ResponseTimeAspect.class);
}
Use the aspect to monitor JDBC SQL statementsThis means that in the user code, all we need to do to enable and disabling this aspect is to invoke these two methods. Here we will monitor the executions of all JDBC statements:
public static void trackResponseTimeOfSqlQueries() {
ResponseTimeAspect.enableMonitoring("call(* java.sql.Statement+.execute*(..))");
... // wait a while to do a recording
ResponseTimeAspect.disableMonitoring();
}
What this pointcut expression (
Note: we could in this specific use-case benefit from retrieving and storing the parameter value to the So now after doing some monitoring you should be able to easily see the data in any JMX console. For example hook in JConsole which you can read more about in this article. Define a deployment scopeFinally, to get this to work in the general case we need to define a deployment scope which defines the set potential join points that we might want to monitor at runtime. This construct gives you (as a application developer or vendor) control over which join points are exposed to the hot deployment API i.e. helps to prevent usage of the hot deployment facilities in specific areas of the application.
This can be done either in the
<aspectwerkz>
<system id="monitoring">
<deployment-scope name="response_time" expression="call(* sample.deployment..*.*(..))"/>
</system>
</aspectwerkz>
Here we have defined a deployment scope that picks out all method calls in our sample application, which means that we can safely deploy our In the code above we have an implicit contract that says that we can not define the aspect to be deployed outside a deployment scope. If we do not define a pointcut that is wider than this it is all fine. But we can now use this deployment scope to ensure that we only deploy the aspect at valid points. To do that we need to retrieve a handle to the scope like this (can be done at any point):
DeploymentScope scope = SystemDefinition.getDefinitionFor(loader, systemId).getDeploymentScope("response_time");
Now we can use the
Deployer.deploy(ResponseTimeAspect.class, xmlDef, scope);
Notes on the impact of the deployment scope preparation
The preparation made by the deployment scope construct means in practice that we are simply adding a level of indirection by adding a call to a When we do undeploy of an aspect, if this aspect is the last one that affects the join point, then the class' bytecode will be reverted to the same state it had before any aspect was deployed. ResourcesMore info about the JMX ResponseTimeAspect
The code for the monitoring aspect is based on the implementation of the You can also check out the complete AWare project which has some tests for the JMX module. Info about how to check out the sources can be found here. More info about the Deployer Module
I have not written any specific sample application for this article but if you want you can look at and run the tests for the deployer module in the AspectWerkz distribution. You can download the distribution here. The tests are in
The I´m facing some problems with the API.. isn´t it in org.codehaus.aspectwerkz... ? Thanks a lot. --Daniel, July 18, 2006 08:51 PM
Hello String xmldef = ""; Deployer.deploy(MyAspect.class, xmldef) everything seem to work correctly but the weaving is not done. I'm getting the message telling that the aspect has been deployed in such class loader, but I'm not getting the expected results. I tried all sorts of joinpoints it does not change anything, no weaving is made. ps: there is no need to use the aop.xml file when I use Deployer.deploy(MyAspect.class, xmldef) am I wrong? If anybody can help me with or have any idea about what can the problem be, I would be very greatful. --Omar, December 16, 2006 11:02 PM
Post a comment
|