Using Code Generation for Dynamic Proxies
Having given code generation a hard time in a previous post, there is one area, where I can definitely see Code Generation providing a valuable solution - Dynamic Proxies. Code Generation typically falls short because it is used within the design cycle and is a bit like baking a cake - its a bit hard to add raisins once you've baked it! With Dynamic Proxies however Code Generation is used at runtime and is a whole different kettle of fish.
What are Proxies? You have a class, which you would like to serialize, add security, logging or maybe even thread locking. In each of these scenarios you typically which to apply logic to public properties and methods (although it is sometimes necessary to serialize private fields). A proxy class will encapsulate our class and expose the classes methods itself, typically by implementing the same interface as the class.
An example:
// class stub
public class Person implements IPerson
{
public String Fullname;
}
// proxy stub
public class ProxyPerson implements IPerson
{
public IPerson Person;
public String Fullname
{
// some proxy logic
return Person.FullName;
}
}
The Person class implements the IPerson interface and the proxy class also implements IPerson interface as well as exposing the original Person class.
What is a Dynamic Proxy? Simple a proxy class generated dynamically at Runtime.
How does it work? We specify the class we wish to generate a proxy for. In .Net this is achieved by decorating the class and its methods with Attributes (does Java have attributes?) When we run our code our proxy generator then reads the attributes and uses them to generate the proxy class e.g.
IPerson personProxy = ProxyGenerator.Proxy(new Person());
We can then us the personProxy instead of the original class.
This sort of technique could also allow us to decouple other functionality from a class such as Equals, GetHashCode, Clone etc leaving our core class less cluttered with Utility functions.
The Person example with Attributes:
// class stub
public class Person implements IPerson
{
[RequiredForEquals()]
public String Fullname;
}
All properties marked with a RequiredForEquals Attribute can be picked up and compared. The comparison code would look something like:
Equalizer personEqualizer = new Equalizer(typeof(Person));
personEqualizer.Equals(person1, person2);
Behind the scenes the Equalizer would use Reflection to read the Attribute and Code Generation to generate our Equlas code before the Equals operation is performed.
// class stub
public class Person implements IPerson
{
public String Fullname;
}
But I can do this with Reflection only! Yup, but Reflecting over a bunch of classes, methods and attributes takes time - generating the proxy and caching it can allow the same proxy to be reused over and over again, with a little overhead on the proxy generation.
Performance
Both Reflection and Code Generation are costly operations, and therefore not something to be undertaken lightly, however, for all but the most time critical functionality they can be optimised by creating the equalizer when the program is loaded (by making the equalizer static).
A real life example, to the best of my knowledge this is how the .Net Frameworks XmlSerializer works. By making the serializer static I managed to improve my serialization code by ten times (originally a 3 second operation became a 0.3 second operation - a significant improvement!)
I have been tempted, but not found time/reason to create a library for creating dynamic proxies. IBM has a interesting Java post on this very topic.
0 Comments:
Post a Comment
<< Home