JRebel	
  Under	
  the	
  Covers	
  
How	
  is	
  it	
  even	
  possible?	
  
Simon	
  Maple	
  -­‐	
  @sjmaple	
  @sjmapleSimon Maple
Make a change
Compile
Build
Deploy
Observe the result
Take some
coffee
Avg: 3 min
state
external
serializable
temporary
derivative
How can I reload a single
class preserving the state?
ClassLoader API
How to reload web application?
(and preserve state)
Classes
Libraries
OldClassLoader NewClassLoader
Sevlet
New
Classes
New
Libraries
Sevlet
Session Session
init()
App
State
App
State
Serialize/deserialize
OldClassLoader NewClassLoader
Sevlet
New
Classes
New
Libraries
Sevlet
Session Session
App
State
App
State
Class loaders are good for
isolation, but suck at
reloading the code …
(and perfect for memory leaks)
Leaking ClassLoaders
Hello, HotSwap!
Hotswapping methods since 2002
M. Dmitriev. Safe class and data evolution in large and long-lived java[tm] applications. Technical report, Mountain View, CA, 2001.
The	
  Heap	
  &	
  Garbage	
  CollecBon	
  
Hello, JRebel!
Improving HotSwap since 2007
Demo Time!
HotSwap	
   JRebel	
  
Changing	
  method	
  bodies	
  
Adding/removing	
  methods	
  
Adding/removing	
  constructors	
  
Adding/removing	
  fields	
  
Adding/removing	
  annotaBons	
  
Changing	
  superclass	
  
Adding/removing	
  interfaces	
  
How does it work???
The
engine
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
public class C extends X {
int y = 5;
int method1(int x) {
return x + y;
}
void method2(String s) {
System.out.println(s);
}
}
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");
}
}
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");
}
}
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();
}
//...
}
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;
}
//...
}
JRebel Reloading
static { }
Adding new static fields
Removing static fields
Changing values of static fields
Factories
etc
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
“package” visibility
package -> public -> package
concurrency
synchronized volatile
Object.wait() Object.notify()
serialization
Serializable Externalizable
transient
reflection
Class, Method, Field,
Constructor, Proxy
The
Ecosystem
Javassist: binary patching
for fun and profit
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
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();
}
}
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();
}
}
JRebel Plugins
@Path(“/”)
public String foo() {
return “Foo”;
}
@Path(“/foobar”)
public String foo() {
return “FooBar”;
}
JRebel	
  
core	
  
JRebel	
  
Spring	
  
plugin	
  
Remote?
THE IMPACT
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.”
Questions?
@sjmaple
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

DevoxxPL: JRebel Under The Covers