一、定义:为其他对象提供一种代理以控制对这个对象的访问。
二、场景:
(1)系统里有一个BUG,客户发现后,找到支持人员,再由支持人员找到对应的开发。首先找到支持人员,支持人员判断是不是系统BUG可以加一些判断,然后处理由开发人员具体处理,解决以后支持人员又告诉客户你的问题我解决了。
(2)你去超市买东西,其实东西是由工厂生产的,超市就是你和工厂之间的代理。
三、分析:
Spring AOP 声明式事物管理 就是这个应用,代理其实就是“我有前边作点事,我有后边作点事,中间你在作”
一般体现在对于,权限、日志、执行时间等
四、静态代理与动态代理
静态代理:分为聚合和继承
聚合一定比继承好,对于代理的扩展性强。但是静态代理必须知道对于那个需要代理。那如果有许多需要代理,那我需要写很多代理类。
动态代理:对任何类动态的生成代理对象。在内存中生成一份字节码。
五、类图:
静态代理代码
public interface Moveable {
void move();
}
public class Tank implements Moveable {
@Override
public void move() {
System.out.println("TanK moving........");
}
}
public class TanklogProxy implements Moveable {
private Moveable t;
public TanklogProxy(Moveable t) {
super();
this.t = t;
}
@Override
public void move() {
System.out.println("start move........");
t.move();
System.out.println("end move......");
}
}
public class TanktimeProxy implements Moveable {
private Moveable t;
public TanktimeProxy(Moveable t) {
super();
this.t = t;
}
@Override
public void move() {
long time1 = System.currentTimeMillis();
System.out.println("time1=" + time1);
t.move();
long time2 = System.currentTimeMillis();
System.out.println("time2=" + time2);
System.out.println("运行时间为:" + (time2 - time1));
}
}
public class TestTank {
public static void main(String[] args) {
Tank t = new Tank();
Moveable move = new TanktimeProxy(t);
Moveable movet = new TanklogProxy(move);
movet.move();
}
}
动态代理代码:
public interface InvocationHandler {
void invoke(Object o,Method m);
}
public class LogInvocationHandler implements InvocationHandler {
private Object target;
public LogInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o, Method m) {
System.out.println("Tank start...........");
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Tank stop..............");
}
}
public interface Moveable {
void move();
}
public class Tank implements Moveable{
@Override
public void move() {
int a = 5;
int b = 6;
int c = 0;
int d = 0;
for (int i = 0; i < 1000; i++) {
d = i;
}
c = ((a+b)/2)*12;
System.out.println("TanK moving..Tank 的速度是"+c);
}
}
public class Proxy {
public static Object newProxyIntenct(Class infac, InvocationHandler h)
throws Exception {
String br = "\r\n";
String methString = "";
Method[] method = infac.getMethods();
for (Method m : method) {
methString =
" @Override" + br + " public void " + m.getName()
+ "() {" + br + " try {" + br + " Method md ="
+ infac.getName() + ".class.getMethod(\"" + m.getName()
+ "\");" + br + " h.invoke(this,md);" + br
+ " }catch (Exception e){ " + br
+ " e.printStackTrace();" + br + " }" + br
+ " }";
}
String src = "package "+infac.getPackage().getName()+";" + br
+ "import java.lang.reflect.Method;" + br
+ "public class $Proxy implements " + infac.getName() + "{"
+ br + " private InvocationHandler h;"
+ br + " public $Proxy(InvocationHandler h) {" + br
+ " super();" + br + " this.h = h;" + br + " }"
+ br + br + methString + br + "}";
MakFileUtil.createFile("D:/src/doproxy");
// 生成java文件
String fileName = "D:\\src\\doproxy\\$Proxy.java";
System.out.println(fileName);
File file = new File(fileName);
FileWriter fWriter = new FileWriter(file);
fWriter.write(src);
fWriter.flush();
fWriter.close();
// 生成class文件,jdk6提供的工具类
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// System.out.println(compiler.getClass().getName());
StandardJavaFileManager fileManager = compiler.getStandardFileManager(
null, null, null);
Iterable units = fileManager.getJavaFileObjects(fileName);
CompilationTask task = compiler.getTask(null, fileManager, null, null,
null, units);
task.call();
fileManager.close();
// 装载到内存,生成新对象
URL[] urls = new URL[] { new URL("file:/" + "D:\\src\\") };
URLClassLoader loader = new URLClassLoader(urls);
Class c = loader.loadClass("doproxy.$Proxy");
// 通过有参的构造器反射生成代理类的实例
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object obj = (Object) ctr.newInstance(h);
return obj;
}
}
public class MakFileUtil {
public static void createFile(String pathstr) throws IOException {
// 创建多级目录
String path = pathstr;
// 为指定字符串构造一个 string tokenizer。 "/"字符是分隔标记的分隔符。分隔符字符本身不作为标记。
StringTokenizer st = new StringTokenizer(path, "/");
String path1 = st.nextToken() + "/";
String path2 = path1;
while (st.hasMoreTokens()) {
path1 = st.nextToken() + "/";
path2 += path1;
File inbox = new File(path2);
if (!inbox.exists())
inbox.mkdir();
}
}
}
public class TestTank {
public static void main(String[] args) throws Exception {
Tank t = new Tank();
Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,
new TimeInvocationHandler(t));
Moveable moveable2 = (Moveable) Proxy.newProxyIntenct(Moveable.class,
new LogInvocationHandler(moveable));
moveable2.move();
}
}
代理模式装饰者模式的区别
装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,并不提供对象本身的增强功能二者的实现机制确实是一样的,可以看到他们的实例代码重复是很多的。但就语义上说,这两者的功能是相反的,模式的一个重要作用是简化其他程序员对你程序的理解,