Programmer's Survival Kit: Code Injection for Troubleshooting, JavaZone 2011

Embed Size (px)

DESCRIPTION

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/

Citation preview

  • 1. Programmer's Survival Kit:Code Injection for Troubleshooting Jakub Hol, Iterate AS http://bit.ly/codeinject

2. Learn code injection it can save your day! 3. The power of code injection Code injectionaspect-oriented programming (AOP*):

  • Modify existingbinaryclasses at build/load time

4. Inject the same code into one or multiple places (DRY) 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 6. 3 tools, 2 (3) examples 7. 1. The omnipresent Java Proxy

  • In JRE java.lang.reflect.*

8. Not true AOP, applied manually 9. Can only proxy interfaces 10. Verbose 11. Client JDBC code: PreparedStatement rawStmt = c.prepareStatement( "INSERT ..." ); PreparedStatement loggingStmt =(PreparedStatement) Proxy.newProxyInstance(...,newBatchLogger(rawStmt)); for( inti = 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. classBatchLoggerimplements InvocationHandler{ publicObjectinvoke (Object proxy , Method method , Object[] args)throwsThrowable { try{ return method.invoke ( this . target , args);}catch(BatchUpdateException e) { } } ... Ex.: Log data of a failed batch (1) 13. classBatchLoggerimplements InvocationHandler{ publicObjectinvoke (Object proxy , Method method , Object[] args)throwsThrowable { if(isSetSomething(method)) { /* rememberargs =column */ } if(isAddBatch(method)) { /*adda new row */ } try{ return method.invoke ( this . target , args);}catch(BatchUpdateException e) { /*logrememberedrows in the batch*/ throwe; } finally{ if(isExecuteBatch(method)) { /*reset rememberedrows */ } } } ... Ex.: Log data of a failed batch (2) 14.

  • No run-time dependencies

15. Build-time weaving 16. Somehow low-level 17. Limited power 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 19. 3. The almighty AspectJ

  • Full-fledged AOP

20. Build-time/load-time weaving 21. Weaving with Ant or Java agentlib 22. Depends on AspectJ libraries at the run-time 23. @Aspect public classLoggingAspect { @Around ( "execution(private void TooQuiet3rdPartyClass.failingMethod(Object))" ) publicObject interceptAndLog(ProceedingJoinPoint invocation)throwsThrowable { try{ returninvocation.proceed(); }catch(Exception e) { thrownew RuntimeException( "Failed for: "+ invocation.getArgs()[0] , e); } } } Ex.: Include argument in exception 24. What it can do

  • Troubleshooting: Improved logging, ...

25. Cross-cutting concerns: Security, transactions, traits, ... - see EJBs 26. Testing:code coverage, mutation testing, ... 27. Code injection/AOP is great but don'toveruse it see Glassbox.sf.net 28. Thank you!

  • Much more detailed explanation with more topics and a link to full source codes:

29. http://bit.ly/codeinject 30. feedback via the blog post's comments welcomed! 31. Bonus slides 32. // Advice my.example.TargetClass.myMethod(..) with a before and afteradvices finalClassPool pool = ClassPool. getDefault (); finalCtClass compiledClass = pool.get( "my.example.TargetClass" ); finalCtMethod method =compiledClass .getDeclaredMethod( "myMethod" ); method.addLocalVariable( "startMs" , CtClass. longType ); method.insertBefore( "startMs = System.currentTimeMillis();" ); method.insertAfter( "{final long endMs = System.currentTimeMillis(); System.out.println("Executed in ms: " + (endMs-startMs));}" ); compiledClass.writeFile( "/tmp/javassist/modifiedClassesFolder" ); // Enjoy the new / tmp /javassist/my/example/TargetClass.class Ex: Performance monitoring withJavassist