Dynamic Proxy
Java’s got its own proxy support right in the java.lang.reflect package. With this package, Java lets you create a proxy class on the fly and on demand that implements one or more interfaces and forwards method invocations to a class that you specify. Because the actual proxy class is created at runtime, we refer to this Java technology as a dynamic proxy.
Here we use Java’s dynamic proxy to create a protection proxy.
Because Java creates the Proxy class for you, you need a way to tell the Proxy class what to do. You can’t put that code into the Proxy class like we did before, because you’re not implementing one directly. So, if you can’t put this code in the Proxy class, where do you put it? In an InvocationHandler. The job of the InvocationHandler is to respond to any method calls on the proxy. Think of the InvocationHandler as the object the Proxy asks to do all the real work after it has received the method calls.
InvovationHandler: implement the behavior of the proxy. Java will take care of creating the actual proxy class and object; we just need to supply a handler that knows what to do when a method is called on it.
Dynamic Proxy Diagram

Implementation
Creating a Subject interface:
public interface Person {
String getName();
String getGender();
String getInterests();
int getGeekRating();
void setName(String name);
void setGender(String gender);
void setInterests(String interests);
void setGeekRating(int rating);
}Creating a Real Subject:
public class PersonImpl implements Person {
String name;
String gender;
String interests;
int rating;
int ratingCount = 0;
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String getInterests() {
return interests;
}
public int getGeekRating() {
if (ratingCount == 0) return 0;
return (rating/ratingCount);
}
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setInterests(String interests) {
this.interests = interests;
}
public void setGeekRating(int rating) {
this.rating += rating;
ratingCount++;
}
}Creating Owner Concrete InvocationHandler:
import java.lang.reflect.*;
public class OwnerInvocationHandler implements InvocationHandler {
Person person;
public OwnerInvocationHandler(Person person) {
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException {
try {
if (method.getName().startsWith("get")) {
return method.invoke(person, args);
} else if (method.getName().equals("setGeekRating")) {
throw new IllegalAccessException();
} else if (method.getName().startsWith("set")) {
return method.invoke(person, args);
}
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}Creating Non-Owner Concrete InvovationHandler:
import java.lang.reflect.*;
public class NonOwnerInvocationHandler implements InvocationHandler {
Person person;
public NonOwnerInvocationHandler(Person person) {
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException {
try {
if (method.getName().startsWith("get")) {
return method.invoke(person, args);
} else if (method.getName().equals("setGeekRating")) {
return method.invoke(person, args);
} else if (method.getName().startsWith("set")) {
throw new IllegalAccessException();
}
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}Testing:
import java.lang.reflect.*;
import java.util.*;
public class MatchMakingTestDrive {
/* Name, Person Object */
HashMap<String, Person> datingDB = new HashMap<String, Person>();
public static void main(String[] args) {
MatchMakingTestDrive test = new MatchMakingTestDrive();
test.drive();
}
public MatchMakingTestDrive() {
initializeDatabase();
}
public void drive() {
Person joe = getPersonFromDatabase("Joe Javabean");
Person ownerProxy = getOwnerProxy(joe);
System.out.println("Name is " + ownerProxy.getName());
ownerProxy.setInterests("bowling, Go");
System.out.println("Interests set from owner proxy");
try {
ownerProxy.setGeekRating(10);
} catch (Exception e) {
System.out.println("Can't set rating from owner proxy");
}
System.out.println("Rating is " + ownerProxy.getGeekRating());
Person nonOwnerProxy = getNonOwnerProxy(joe);
System.out.println("Name is " + nonOwnerProxy.getName());
try {
nonOwnerProxy.setInterests("bowling, Go");
} catch (Exception e) {
System.out.println("Can't set interests from non owner proxy");
}
nonOwnerProxy.setGeekRating(3);
System.out.println("Rating set from non owner proxy");
System.out.println("Rating is " + nonOwnerProxy.getGeekRating());
}
/* Takes a real subject and returns proxy for it. Since the proxy has the same interface
as the subject, we return Person. */
Person getOwnerProxy(Person person) {
return (Person) Proxy.newProxyInstance(
/* Class loader for our subject */
person.getClass().getClassLoader(),
/* Set of interfaces the proxy needs to implement */
person.getClass().getInterfaces(),
/* Invocation handler
This is how the handler gets access to the real subject */
new OwnerInvocationHandler(person));
}
Person getNonOwnerProxy(Person person) {
return (Person) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new NonOwnerInvocationHandler(person));
}
Person getPersonFromDatabase(String name) {
return (Person)datingDB.get(name);
}
void initializeDatabase() {
Person joe = new PersonImpl();
joe.setName("Joe Javabean");
joe.setInterests("cars, computers, music");
joe.setGeekRating(7);
datingDB.put(joe.getName(), joe);
Person kelly = new PersonImpl();
kelly.setName("Kelly Klosure");
kelly.setInterests("ebay, movies, music");
kelly.setGeekRating(6);
datingDB.put(kelly.getName(), kelly);
}
}