This presentation is aimed at giving you the knowledge of code injection that you may (or I should rather say "will") need and at persuading you that learning basics of code injection is really worth the little of your time that it takes. I'll present three different real-world cases where code injection came to my rescue, solving each one with a different tool, fitting best the constraints at hand. I'll also provide you with resources to learn the basics and tools easily and quickly.
This is a practical presentation; we won't introduce AOP and will explain code injection only briefly, plunging right into the tools and how they can help you.
See http://theholyjava.wordpress.com/2011/09/07/practical-introduction-into-code-injection-with-aspectj-javassist-and-java-proxy/
5. Lifecycle: Write aspect > weave > run (For AOP check Wikipedia or Spring docs.) * I will use AOP and Code Injection interchangeably, however inaccurate that is
11. Client JDBC code: PreparedStatement rawStmt = c.prepareStatement( "INSERT ..." ); PreparedStatement loggingStmt = (PreparedStatement) Proxy.newProxyInstance(..., new BatchLogger(rawStmt)); for ( int i = 0; i < data. length ; i++) { loggingStmt.setString(1, data[i]); loggingStmt.addBatch(); // end a row, start a new one if (isMultipleOfBatchSize(i)) loggingStmt.executeBatch(); // Logs st. on failure } Ex.: Log data of a failed batch (0)
12. class BatchLogger implements InvocationHandler { public Object invoke (Object proxy , Method method , Object[] args) throws Throwable { try { return method.invoke ( this . target , args); } catch (BatchUpdateException e) { } } ... Ex.: Log data of a failed batch (1)
13. class BatchLogger implements InvocationHandler { public Object invoke (Object proxy , Method method , Object[] args) throws Throwable { if (isSetSomething(method)) { /* remember args = column */ } if (isAddBatch(method)) { /*add a new row */ } try { return method.invoke ( this . target , args); } catch (BatchUpdateException e) { /*log remembered rows in the batch*/ throw e; } finally { if (isExecuteBatch(method)) { /*reset remembered rows */ } } } ... Ex.: Log data of a failed batch (2)
18. Weaving manually / custom Ant task For an example, see the accompanying source code project and blog post. For an alternative w/o most cons see GluonJ. 2. The independent Javassist
32. // Advice my.example.TargetClass.myMethod(..) with a before and after advices final ClassPool pool = ClassPool. getDefault (); final CtClass compiledClass = pool.get( "my.example.TargetClass" ); final CtMethod method = compiledClass .getDeclaredMethod( "myMethod" ); method.addLocalVariable( "startMs" , CtClass. longType ); method.insertBefore( "startMs = System.currentTimeMillis();" ); method.insertAfter( "{final long endMs = System.currentTimeMillis(); System.out.println(amp;quot;Executed in ms: amp;quot; + (endMs-startMs));}" ); compiledClass.writeFile( "/tmp/javassist/modifiedClassesFolder" ); // Enjoy the new / tmp /javassist/my/example/TargetClass.class Ex: Performance monitoring with Javassist
Notas del editor
Short time -> for detailed explanation and more examples see the URL
The key message of this presentation: Every developer should know and be able to use AOP for earlier or later it will be incredibely useful to him/her.
The great things about code injection
- !!! Start examples by asking how they would solve the challenge - Not time to go through examples in detail -> check blog, source codes. I will show 3 different tools - with their pros & cons - on 2 (3) real-world use cases. - each useful under different conditions
1. What is (Java) proxy 2. Pros: Available everywhere. Can be set up at runtime. Cons: Not true AOP – only interfaces, apply manually. Only at runtime. Very limited and verbose.
Case: Inserting 1000s of rows using batches of ~100 for efficiency and it's failing for one of the batches but the exception doesn't tell you which batch and what data => can't find out which record of the 1000s is causing it. => You'd need to remember data going into each batch and log them upon failure. => Use a dynamic proxy ...
To create a proxy you need to implement an InvocationHandler: - 1 method, invoke , taking reflect.* objects with info about the invocation, called for each method - you can use it to delegate the call to the proxied target object So far we just delegate to the original object.
Write code to add some behavior.
Having no run-time dependencies on Javassist may be crucial if your organization doesn't easily approve the deployment of new (open-source) libraries – or if you want to keep your application small.
Compile- x build-time weaving Powerful – add members, inject into static methods, ... Eclipse AJDT
The less powerful but easier to use @Aspect syntax.
Quite less powerful than AspectJ Requires no runtime dependencies => no need to ask permission for another OOS library (a legal issue in large corporations) See TBD:LINK2BLOG