动态代理需要一个调用处理程序(invocation handler)来处理方法的调用。调用处理程序是一个简单的类,只需要实现InvocationHandler接口即可。这个接口里只有一个invoke方法,允许你自己控制整个调用过程。下面举例说明:
ArithmeticCalculator
package edu.xaut.jzd.spring;
public interface ArithmeticCalculator {
public double add(double a,double b);
public double sub(double a,double b);
public double mul(double a,double b);
public double div(double a,double b);
}
ArithmeticCalculatorImpl:
package edu.xaut.jzd.spring;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public double add(double a, double b) {
double result=a+b;
System.out.println(a+"+"+b+"="+result);
return result;
}
@Override
public double sub(double a, double b) {
double result=a-b;
System.out.println(a+"-"+b+"="+result);
return result;
}
@Override
public double mul(double a, double b) {
double result=a*b;
System.out.println(a+"*"+b+"="+result);
return result;
}
@Override
public double div(double a, double b) {
double result=a/b;
System.out.println(a+"/"+b+"="+result);
return result;
}
}
package edu.xaut.jzd.spring;
public class UnitCalculatorImpl implements UnitCalculator {
@Override
public double kilogramToPound(double kilogram) {
// TODO Auto-generated method stub
double pound=kilogram*2.2;
System.out.println(kilogram+" kilogram= "+pound+" pound");
return pound;
}
@Override
public double kilometerToMile(double kilometer) {
// TODO Auto-generated method stub
double mile=kilometer*0.62;
System.out.println(kilometer+" kilometer= "+mile+" mile");
return mile;
}
}
下面为日志代理和验证代理类:
CalculatorLoggingHandler
package edu.xaut.jzd.spring;
import java.util.Arrays;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CalculatorLoggingHandler implements InvocationHandler {
private Log log=LogFactory.getLog(this.getClass());
private Object target;
public CalculatorLoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
log.info("The method "+method.getName()+"() begins with "+Arrays.toString(args));
Object result=method.invoke(target, args);
log.info("The method "+method.getName()+"() ends with "+result);
return result;
}
public static Object createProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new CalculatorLoggingHandler(target));
}
}
CalculatorValidationHandler
package edu.xaut.jzd.spring;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CalculatorValidationHandler implements InvocationHandler {
private Object target;
public CalculatorValidationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
for(Object arg:args){
validate((Double)arg);
}
Object result=method.invoke(target, args);
return result;
}
private void validate(double a){
if(a<0){
throw new IllegalArgumentException("Positive numbers only");
}
}
//创建代理对象
public static Object createProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new CalculatorValidationHandler(target));
}
}
下面是Main函数:
package edu.xaut.jzd.spring;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ArithmeticCalculator arithmeticCalculatorImpl=new ArithmeticCalculatorImpl();
ArithmeticCalculator arithmeticCalculator=(ArithmeticCalculator)CalculatorValidationHandler.createProxy(
CalculatorLoggingHandler.createProxy(arithmeticCalculatorImpl));
arithmeticCalculator.add(1.2, 1.3);
arithmeticCalculator.sub(1.2, 1.3);
UnitCalculator unitCalculatorImpl=new UnitCalculatorImpl();
UnitCalculator unitCalculator=(UnitCalculator)CalculatorValidationHandler.createProxy(
CalculatorLoggingHandler.createProxy(unitCalculatorImpl));
unitCalculator.kilogramToPound(1);
}
}
测试输出为:
2012-11-17 9:25:24 edu.xaut.jzd.spring.CalculatorLoggingHandler invoke
信息: The method add() begins with [1.2, 1.3]
2012-11-17 9:25:24 edu.xaut.jzd.spring.CalculatorLoggingHandler invoke
信息: The method add() ends with 2.5
1.2+1.3=2.5
2012-11-17 9:25:24 edu.xaut.jzd.spring.CalculatorLoggingHandler invoke
信息: The method sub() begins with [1.2, 1.3]
1.2-1.3=-0.10000000000000009
2012-11-17 9:25:24 edu.xaut.jzd.spring.CalculatorLoggingHandler invoke
信息: The method sub() ends with -0.10000000000000009
2012-11-17 9:25:24 edu.xaut.jzd.spring.CalculatorLoggingHandler invoke
信息: The method kilogramToPound() begins with [1.0]
1.0 kilogram= 2.2 pound
2012-11-17 9:25:24 edu.xaut.jzd.spring.CalculatorLoggingHandler invoke
信息: The method kilogramToPound() ends with 2.2
要创建一个具有调用处理程序的动态代理实例,就须调用静态方法Proxy.newProxyInstance().
这个方法的第一个参数是ClassLoader,负责注册该代理。第二个参数由该代理需要实现的接口组成,通常需要代理目标类的所有接口。最后一个参数是处理方法调用的调用处理程序。
在Main类里,可以使用验证代理包装日志代理形成一个代理链。所有计算器方法的调用都先要经过验证代理,再经过日志代理。这意味着验证先于日志执行。如要调换顺序,则用日志代理包装验证代理。