Java反射包(java.lang.reflect)给编程带来了很多的灵活性,代理能够维持类的原貌,很好地解决java灵活性较差的问题。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
静态代理:
抽象接口:
package DesignPattern.staticProxy;
public interface Hello {
public abstract void say();
}
实现类:
package DesignPattern.staticProxy;
public class HelloImpl implements Hello{
// @Override
public void say() {
// TODO Auto-generated method stub
System.out.println("lcx hello");
}
}
代理类:
package DesignPattern.staticProxy;
public class HelloProxy implements Hello{
private Hello hi;
/**
* @param hi
*/
public HelloProxy(Hello hi) {
super();
this.hi = hi;
}
public void say() {
// TODO Auto-generated method stub
doBefore();
hi.say();
doAfter();
}
private void doBefore(){
System.out.println("before method invoke");
}
private void doAfter(){
System.out.println("after method invoke");
}
}
测试类:
package DesignPattern.staticProxy;
public class HelloTest {
public static void main(String[] args) {
Hello hw=new HelloImpl();
HelloProxy proxy=new HelloProxy(hw);
proxy.say();
}
}
结果如下:
before method invoke
lcx hello
after method invoke
通过上述4个类,对HelloImpl类实现了改造,完成了对say()方法的包装处理。
动态代理
接口类:
package DesignPattern.dynamicProxy;
public interface Hello {
public abstract void say();
}
实现类:
package DesignPattern.dynamicProxy;
public class HelloImpl implements Hello{
// @Override
public void say() {
// TODO Auto-generated method stub
System.out.println("lcx hello");
}
}
代理类:
package DesignPattern.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class HelloHandler implements InvocationHandler {
private Object obj;
/**
* @param obj
*/
public HelloHandler(Object obj) {
super();
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
doBefore();
Object res=method.invoke(obj, args);
doAfter();
return res;
}
private void doBefore(){
System.out.println("before method invoke");
}
private void doAfter(){
System.out.println("after method invoke");
}
}
测试类:
package DesignPattern.dynamicProxy;
import java.lang.reflect.Proxy;
public class HelloTest {
public static void main(String[] args) {
Hello hw=new HelloImpl();
HelloHandler handler=new HelloHandler(hw);
Hello proxy=(Hello) Proxy.newProxyInstance(hw.getClass().getClassLoader(), hw.getClass().getInterfaces(), handler);
proxy.say();
}
}
最后打印结果
before method invoke
lcx hello
after method invoke
Proxy源码研究
Proxy中主要方法是newProxyInstance方法,代码如下:
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler. This method is equivalent to:
*
* Proxy.getProxyClass(loader, interfaces).
* getConstructor(new Class[] { InvocationHandler.class }).
* newInstance(new Object[] { handler });
*
*
* Proxy.newProxyInstance
throws
* IllegalArgumentException
for the same reasons that
* Proxy.getProxyClass
does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to getProxyClass
* are violated
* @throws NullPointerException if the interfaces
array
* argument or any of its elements are null
, or
* if the invocation handler, h
, is
* null
*/
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
注释中:Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocationhandler.
大致意思是:返回一个指定接口与方法处理者的代理类对象,实际上就是反射。
Class cl = getProxyClass(loader, interfaces)实现了获取Proxy类对应的对象。
cons.newInstance(new Object[] { h })实现了通过相关的类得到Proxy对象。
总结,静态代理与动态代理区别:
1. 静态代理原理是组合,动态代理原理是反射。
2. 静态代理灵活性仍然较差,只能对一个方法进行代理。而动态代理可以对多方法进行处理。
3. 在代码维护过程中,如果对类方法名称等进行修改(如将方法名修改为say1()),或者增减方法,动态代理的代理类无需修改任何代码,静态代理则不然。我们可以看到HelloHandler代码中,没有包含任何与Hello相关的东西,所以内容完全有obj传入。
总之,动态代理的好处全部源于反射机制。