devoxxpl: jrebel under the covers

54
JRebel Under the Covers How is it even possible?

Upload: simon-maple

Post on 03-Aug-2015

220 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: DevoxxPL: JRebel Under The Covers

JRebel  Under  the  Covers  How  is  it  even  possible?  

Page 2: DevoxxPL: JRebel Under The Covers

Simon  Maple  -­‐  @sjmaple  @sjmapleSimon Maple

Page 3: DevoxxPL: JRebel Under The Covers
Page 4: DevoxxPL: JRebel Under The Covers
Page 5: DevoxxPL: JRebel Under The Covers

Make a change Compile

Build

Deploy

Observe the result

Take some coffee

Avg: 3 min

Page 6: DevoxxPL: JRebel Under The Covers
Page 7: DevoxxPL: JRebel Under The Covers

state external

serializable

temporary

derivative

Page 8: DevoxxPL: JRebel Under The Covers

How can I reload a single class preserving the state?

Page 9: DevoxxPL: JRebel Under The Covers

ClassLoader API

Page 10: DevoxxPL: JRebel Under The Covers
Page 11: DevoxxPL: JRebel Under The Covers

How to reload web application? (and preserve state)

Page 12: DevoxxPL: JRebel Under The Covers

Classes

Libraries

OldClassLoader NewClassLoader

Sevlet New Classes New

Libraries

Sevlet

Session Session init()

App State

App State

Serialize/deserialize

Page 13: DevoxxPL: JRebel Under The Covers

OldClassLoader NewClassLoader

Sevlet New Classes New

Libraries

Sevlet

Session Session

App State

App State

Page 14: DevoxxPL: JRebel Under The Covers

Class loaders are good for isolation, but suck at reloading the code … (and perfect for memory leaks)

Page 15: DevoxxPL: JRebel Under The Covers
Page 16: DevoxxPL: JRebel Under The Covers

Leaking ClassLoaders

Page 17: DevoxxPL: JRebel Under The Covers

Hello, HotSwap! Hotswapping methods since 2002

Page 18: DevoxxPL: JRebel Under The Covers

M. Dmitriev. Safe class and data evolution in large and long-lived java[tm] applications. Technical report, Mountain View, CA, 2001.

Page 19: DevoxxPL: JRebel Under The Covers

The  Heap  &  Garbage  CollecBon  

Page 20: DevoxxPL: JRebel Under The Covers

Hello, JRebel! Improving HotSwap since 2007

Page 21: DevoxxPL: JRebel Under The Covers

Demo Time!

Page 22: DevoxxPL: JRebel Under The Covers

HotSwap   JRebel  Changing  method  bodies  Adding/removing  methods  Adding/removing  constructors  Adding/removing  fields  Adding/removing  annotaBons  Changing  superclass  Adding/removing  interfaces  

Page 23: DevoxxPL: JRebel Under The Covers

How does it work???

Page 24: DevoxxPL: JRebel Under The Covers

The engine

Page 25: DevoxxPL: JRebel Under The Covers

ClassA

+field1 +field2 +field3

+method1(n:int) +method2(s:String) +method3(z:double)

ClassA

+field1 +field2 +field3 +proxy methods

ClassA0

+method1(n:int) +method2(s:String) +method3(z:double)

Transformer

Page 26: DevoxxPL: JRebel Under The Covers

public class C extends X { int y = 5; int method1(int x) { return x + y; } void method2(String s) { System.out.println(s); }}

Page 27: DevoxxPL: JRebel Under The Covers

public class C extends X { int y = 5; int method1(int x) { Object[] o = new Object[1]; o[0] = x; return Runtime.redirect(this, o, "C", "method1", "(I)I"); } void method2(String s) { Object[] o = new Object[1]; o[0] = s; return Runtime.redirect( this, o, "C", "method2", "(Ljava/lang/String;)V"); }}

Page 28: DevoxxPL: JRebel Under The Covers

public abstract class C0 { public static int method1(C c, int x) { int tmp1 = Runtime.getFieldValue(c, "C", "y", "I"); return x + tmp1; } public static void method2(C c, String s) { PrintStream tmp1 = Runtime.getFieldValue( null, "java/lang/System", "out", "Ljava/io/PrintStream;"); Object[] o = new Object[1]; o[0] = s; Runtime.redirect( tmp1, o, "java/io/PrintStream;", "println", "(Ljava/lang/String;)V"); }}

Page 29: DevoxxPL: JRebel Under The Covers

public class C extends X { int y = 5; int method1(int x) { return x + y; } //...}

public class C extends X { int y = 5; int z() { return 10; } int method1(int x) { return x + y + z(); } //...}

Page 30: DevoxxPL: JRebel Under The Covers

public class C1 { public static int z(C c) { return 10; } public static int method1(C c, int x) { int tmp1 = Runtime.getFieldValue(c, "C", "y", "I"); int tmp2 = Runtime.redirect(c, null, "C", "z", "(V)I"); return x + tmp1 + tmp2; } //...}

Page 31: DevoxxPL: JRebel Under The Covers

JRebel Reloading

Page 32: DevoxxPL: JRebel Under The Covers
Page 33: DevoxxPL: JRebel Under The Covers
Page 34: DevoxxPL: JRebel Under The Covers

static { }

Adding new static fields Removing static fields Changing values of static fields Factories etc

Page 35: DevoxxPL: JRebel Under The Covers

package a;public class A { int say() {return 1;}}

package a;class Test { public static void main(String args[]) { a.A a = new b.B(); System.out.println(a.say()); }}

package b;public class B extends a.A { int say() {return 2;}}

An Exercise

Page 36: DevoxxPL: JRebel Under The Covers

“package” visibility

package -> public -> package

Page 37: DevoxxPL: JRebel Under The Covers

concurrency

synchronized volatile

Object.wait() Object.notify()

Page 38: DevoxxPL: JRebel Under The Covers

serialization

Serializable Externalizable

transient

Page 39: DevoxxPL: JRebel Under The Covers

reflection

Class, Method, Field,

Constructor, Proxy

Page 40: DevoxxPL: JRebel Under The Covers
Page 41: DevoxxPL: JRebel Under The Covers

The Ecosystem

Page 42: DevoxxPL: JRebel Under The Covers

Javassist: binary patching for fun and profit

Page 43: DevoxxPL: JRebel Under The Covers

import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;

public class Agent { public static void premain(String args, Instrumentation inst) throws Exception { inst.addTransformer(new ClassFileTransformer { }); }}

java  –javaagent:agent.jar  …  

META-INF/MANIFEST.MF Premain-Class: Agent

Page 44: DevoxxPL: JRebel Under The Covers

new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){

ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer));

transformClass(ct, cp);

return ct.toBytecode(); }}

Page 45: DevoxxPL: JRebel Under The Covers

new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){

ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer));

transformClass(ct, cp);

return ct.toBytecode(); }}

Page 46: DevoxxPL: JRebel Under The Covers

JRebel Plugins

Page 47: DevoxxPL: JRebel Under The Covers

@Path(“/”) public String foo() { return “Foo”; }

@Path(“/foobar”) public String foo() { return “FooBar”; }

JRebel  core  

JRebel  Spring  plugin  

Page 48: DevoxxPL: JRebel Under The Covers

Remote?

Page 49: DevoxxPL: JRebel Under The Covers

THE IMPACT

Page 50: DevoxxPL: JRebel Under The Covers

http://zeroturnaround.com/company/case-studies/

“Team velocity was increased by 40.6%, and according to t-test it was a statistically significant difference.”

“Netty and Spring together with JRebel is real pleasure to work with. The value of time saved is over 50% of my development time.”

Page 51: DevoxxPL: JRebel Under The Covers

Questions? @sjmaple

Page 52: DevoxxPL: JRebel Under The Covers
Page 53: DevoxxPL: JRebel Under The Covers
Page 54: DevoxxPL: JRebel Under The Covers

Credits https://www.flickr.com/photos/smemon/4556099850/ https://www.flickr.com/photos/gforsythe/10173857405 https://www.flickr.com/photos/dkshots/6967173295 https://www.flickr.com/photos/reckless_sniper/4545673070 https://www.flickr.com/photos/omcoc/8350510425 https://www.flickr.com/photos/bufivla/3619927485 https://www.flickr.com/photos/39747297@N05/5229733647 http://leadershipelements.files.wordpress.com/2014/01/square-peg-round-hole.jpg