动态代理
动态代理又叫做JDK代理、接口代理。其和静态代理的区别是不需要实现接口。而是直接利用JDK的API动态的在内存中创建代理对象。
在JDK中生成代理对象的API,存在于java.lang.reflect.Proxy
这个包内。JDK实现代理只需要使用
newProxyInstance
方法即可。调用方式如下:
/**
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
*/
static ObjectnewProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loader
:获取当前对象的类加载器,一般方法是固定的。
interfaces
:目标对象实现的借口类型,一般用泛型确认类型。
h
:事件处理,执行目标对象的方法时,会触发事件处理方法,会把当前执行目标对象的方法作为参数传入。
例如:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class },handler);
示例代码:
对象的行为接口:
public interface Caculate {
int add(int a,int b) ;
int sub(int a,int b) ;
int mul(int a,int b) ;
int div(int a,int b) ;
}
目标业务对象类:
public class CaculateImpl implements Caculate {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public int sub(int a, int b) {
return a-b;
}
@Override
public int mul(int a, int b) {
return a*b;
}
@Override
public int div(int a, int b) {
return a/b;
}
}
生成代理对象的代理类:
public class ProxyFactory {
//目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//动态代理模式的关键性代码
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在转调具体目标对象之前,可以执行一些功能处理
print();
System.out.println(">>>>>>>>start"+"||"+method.getName());
//执行目标方法
Object returnValue = method.invoke(target,args);
//在转调具体目标对象之前,可以执行一些功能处理
System.out.println(">>>>>>>>end");
return returnValue;
}
});
}
public void print(){
System.out.println(">>>>>>>>>>You are not alone!");
}
}
测试主函数:
public class Main {
public static void main(String[] args) {
//目标对象
Caculate caculate = new CaculateImpl();
System.out.println(caculate.getClass());
Caculate caculate1 = (Caculate) new ProxyFactory(caculate).getProxyInstance();
System.out.println(caculate1.getClass());
int result = 0;
result = caculate1.add(1,2);
System.out.println(">>>>>>>>>>>>>>>>>"+result);
}
}
编写动态代理模式的步骤:
- 创建接口和实现接口的目标类,
- 实现InvocationHandler接口,重写invoke方法。
- 调用proxy的静态方法
newProxyInstance
方法生产代理实例。 - 使用新生成的代理实例调用目标对象的方法。
优缺点:
优点:
代理对象无需实现接口,不需要写过多的代理类。如果增加方法也不需要在维护目标对象和代理对象,只需要在事件处理器中添加方法判断即可。
缺点:
目标对象要求一定要实现接口。否则就无法使用动态代理。