You will be redirected to our new website in 5 seconds...
If you are not automatically taken to our new web site,
please click on the hyperlink :
http://jodd.org
Jodd
build: 309
updated: Jun 17 2008
 

SourceForge.net Logo

freebsd  Support this project

home Home | download | home Contact | SourceForge | File Releases releases | News news |  
Proxetta
* Never do that by proxy which you can do yourself. (Italian Proverb)
Table of Contents

JDateTime betaProxetta is all about dynamic proxies. Using just Java. In the same way you would code it by yourself. And the only dependency is Jodd & Asm library.

Highlights
  • Proxy definition in pure Java
  • Separated proxy definition & implementation
  • Fast, fast, fast!

Dynamic Proxy
Sorry, documentation is not yet complete and does not provide sufficient information. Please refer to test cases, javadoc and sources for more details.
If you need more info on this particular subject, do not hesitate to demand more documentation.

A dynamic proxy class is a class that wraps target class specified at runtime. Proxy Aspect contains advice and pointcut rules for applying advice. Proxy Advice is the code portion of an aspect, i.e. the logic that replaces crosscutting concern. Pointcut is a set of points in the application where advice should be applied, i.e. which methods will be wrapped by proxy.

In Jodd, proxy is defined by its apsects that might be applied on target methods of target class. If pointcuts match one or more target methods, Proxetta will subclass the target class and override each target method with method that contains advice's code.

Proxetta pointcuts are defined in pure Java, no custom language or XMLs is used, although user might easily extend this.

For an example, let's create proxy over all methods that has been annotated with custom annotation: Log.

Pointcut
ProxyPointcut pointcut = new ProxyPointcut() {
		public boolean apply(MethodSignature msign) {
			List<AnnotationData> anns = msign.getAnnotations();
			for (AnnotationData a : anns) {
				if (a.declaration.equals(Log.class.getName())) {
					return true;
				}
			}
			return false;
		}
	};

ProxyPointcut.apply() should return true if target method is a pointcut and if proxy should wraps it. Since pointcut is written in Java, user may use various ways to define a pointcut. Abstract class ProxyPointcutSupport may help in pointcut definition, since it has several common helper methods, such as checking if method is public, using wildcard match with method name etc. Additionally, there are some common pointcuts already defined, for all setters, getters and all public methods. By the way, MethodSignature provides various information about method, so users may fine-tune on which methods to apply a proxy. And all that in plan Java.

Attention!
Proxetta is also applied on all methods of superclass, up to the Object. However, only public and non-final methods of all superclasses are considered.

Advice

Here comes the fun and unusual part! Advices implement the ProxyAdvice interface that has just one method: execute(). Now, instead of having method arguments of custom type to reference target method and class, its arguments etc, Proxetta introduces special class ProxyTarget for those purposes. But, ProxyTarget methods are dummy and they serves just as macros, that will be replaced by appropriate bytecode! At the end, there is no dependency on ProxyTarget, since all macro methods have been replaced with bytecode, that mimic the code that developer would write by himself!

Lets see this on example:

public class LogProxyAdvice implements ProxyAdvice {

	public Object execute() {
		int totalArgs = ProxyTarget.argumentsCount();
		Class target = ProxyTarget.targetClass();
		String methodName = ProxyTarget.targetMethodName();
		System.out.println(">>>" + target.getSimpleName() + '#' + methodName + ':' + totalArgs);
		Object result = ProxyTarget.invoke();
		System.out.println("<<<" + result);
		return result;
	}
}

To emphasize: ProxyTarget.argumentsCount() (for example) will be replaced by appropriate number of target method arguments. Replacements occur in run-time, during proxy creation, using bytecode manipulation. Therefore, it is not possible to test arguments count get in this way in if block (this can be tested by getting array of all arguments). Once again, all ProxyTarget methods are replaced by appropriate bytecodes! At the end, resulting subclass proxy will really looks like user developed by itself:)

One should not to forget that Proxetta copies advice's constructors, static initialization blocks, fields, etc. Advices should be written carefully, always having in mind that advice's code will be added to the target classes. Common mistake might be accessing package scoped classes from advice, or using static attributes forgetting that this attribute will be copied to all target classes (simply use external class for that).

For now, using inner classes in advices is not supported.

Proxy

Proxy is defined very simply, not much to say about:

	ProxyAspect aspect = new ProxyAspect(LogProxyAdvice.class, pointcut);
			
Working with Proxetta

Let's see now how all this works together.

byte[] fooBytes = Proxetta.withAspects(aspect).createProxy(Foo.class);
Class fooClass = ClassLoaderUtil.defineClass(fooBytes);

or, at once:

Class fooClass = Proxetta.withAspects(aspect).defineProxy(Foo.class);

or, an instance:

Foo foo = Proxetta.withAspects(aspect).createProxyInstance(Foo.class);

These are just basic Proxetta usages. It is possible to provide target class as a string name, or input stream. Moreover, by default, creating proxy on target class still doesn't means that proxy will be created for class methods - if class has no valid pointcuts it will be remain untouched. Of course, this is configurable. Moreover, it is possible to turn on variable proxy class names, so proxy may be created several times and loaded by same class loader. And so on.

How fast is Proxetta?

Due to unique approach that does not use reflection but macro-methods, Proxetta becomes very fast. For example, we took cglib library and created simple proxy (with help of dynaop project). Than in a simple big loop we just invoke proxified method that has single argument.

While cglib version took cca 50 seconds, Proxetta needed only 13 seconds. Of course, using reflection in Proxetta will slows things down, but due to unique approach, many use-cases would not required reflection at all.

Use Proxetta transparently with Petite

Petite container allows an easy way to "hook" on bean registration, where we can use Proxetta to modify the bean type and use enhanced type instead. More details and an example can be found on Petite page.