代理(Proxy)模式标准定义:为其余对象提供一种代理以控制对这个对象的访问。java
代理就是一我的或一个机构表明另外一我的或者一个机构采起行动。某些状况下,客户不想或者不可以直接引用一个对象,代理对象能够在客户和目标对象直接起到中介的做用。客户端分辨不出代理主题对象与真实主题对象。代理模式能够并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不可以建立被代理对象,被代理对象必须有系统的其余角色代为建立并传入。ide
代理模式实现的方式具体有2种。一、经过继承实现;二、经过聚合的方式实现。this
/**url
* @describe: 定义接口.net
*/代理
public interface Animal {对象
public void move();blog
}继承
/**接口
* @describe: 接口实现类
*/
package test.com.java.proxy.example;
public class Persion implements Animal{
public void move() {
System.out.println("不断的移动中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("移动结束...");
}
}
/**
*
* @describe:一、采用继承的方式对Persion进行代理,增长打印方法执行时间的新功能
*/
package test.com.java.proxy.example;
public class PersionExtendsProxy extends Persion{
public void move() {
long start=System.currentTimeMillis();
System.out.println("move() start...");
super.move();
long end=System.currentTimeMillis();
System.out.println("move() end... times:"+(end-start));
}
}
/**
*
* @describe:二、采用聚合的方式对Proxy类进行代理(面向接口的方式代理)
*/
package test.com.java.proxy.example;
public class PersionProxy implements Animal{
private Animal a;
public PersionProxy(Animal a){
this.a=a;
}
@Override
public void move() {
long start=System.currentTimeMillis();
System.out.println("move() start...");
a.move();
long end=System.currentTimeMillis();
System.out.println("move() end... times:"+(end-start));
}
}
package test.com.java.proxy.example;
public class Test {
public static void main(String[] args) {
//采用继承的方式实现代理
Animal proxy=new PersionExtendsProxy();
proxy.move();
System.out.println("----------------------------------");
//采用聚合的方式实现代理
Persion p=new Persion();
Animal proxy1=new PersionProxy(p);
proxy1.move();
}
}
运行结果:
move() start...
不断的移动中...
移动结束...
move() end... times:1000
----------------------------------
move() start...
不断的移动中...
移动结束...
move() end... times:1001
2种实现方式比较:
1)因为java仅支持单继承,因此采用继承的方式实现不够灵活,若是还须要继承其余的类的话,那就费了;
2)若是须要继续增长新的代理功能,那么采用继承的方式的话,就须要不断的继承下去,这样类的层次结构会愈来愈深,维护起来很不方便。
综上所述:采用聚合的方式实现代理比较好。下面咱们讨论下JDK动态代理实现。
JDK动态代理实现以下:
Animal.java、Persion.java文件同上
下面须要咱们自定义一个实现InvocationHandler接口的处理方法类,在要代理的对象方法先后增长适当的逻辑。
package test.com.java.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler{
private Object target;
MyInvocationHandler() {
super();
}
MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object o, Method method,Object[] args) throws Throwable {
System.out.println("o:"+o.getClass().getName());
System.out.println("method:"+method);
System.out.println("args:"+args);
long start=System.currentTimeMillis();
System.out.println("move() start...");
Object result=method.invoke(target, args);
long end=System.currentTimeMillis();
System.out.println("move() end... times:"+(end-start));
System.out.println("result:"+result);
return result;
}
}
/**
*
* @describe:使用JDK动态代理的方式
* @author wenqi 2017年11月26日
*
*/
package test.com.java.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
Animal a=new Persion();
InvocationHandler handler=new MyInvocationHandler(a);
Animal proxy=(Animal) Proxy.newProxyInstance(a.getClass().getClassLoader(), a.getClass().getInterfaces(), handler);
proxy.move();
}
}
运行结果以下:
o:com.sun.proxy.$Proxy0
method:public abstract void test.com.java.proxy.dynamic.Animal.move()
args:null
move() start...
不断的移动中...
move() end... times:1002
result:null
生成动态代理Class文件相似以下:
public class Proxy {
public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
String methodStr = "";
String rt = "\r\n";
Method[] methods = infce.getMethods();
for(Method m : methods) {
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
"}";
}
String src =
"package com.bjsxt.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" InvocationHandler h;" + rt +
methodStr +
"}";
String fileName =
"d:/src/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//compile
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//load into memory and create an instance
URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("$Proxy1");
System.out.println(c);
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h);
return m;
}
}
Spring中aop是动态代理具体应用,相关文章以下: