一、代理模式
定义
为其他对象提供一种 代理 以控制对这个对象的访问。. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。. 著名的代理模式例子为 引用计数 (英语:reference counting)指针对象。. 当一个复杂对象的多份副本须存在时,代理模式可以结合 享元模式 以减少存储器用量。. 典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。. 而作用在代理者的运算会转送到原本对象。. 一旦所有的代理者都不存在时,复杂对象会被移除。
二、静态代理
(一)静态代理
在学习代理模式时,我使用一个瓜甜不甜案例;
1.接口:Transportation(交通工具) 自定义接口,定义run()方法。
2.被代理类:Car类实现Transportation接口。
3.代理类:CarHanlderWork(事务代理类)CarHanlderTime(时间代理类)。
4.测试类:Client
(二)静态代理简单实现
继承实现静态代理:
public interface Tranfertaction {
void run();
}
/**
* 需求,需要给实现了Transportation接口的子类里重写的run方法加上前后日志记录
* 可以通过继承的方式给Car创建一个代理对象。并重写Car的方法,在重写的方法中调用父类的逻辑。并在调用前后加上日志记录
*/
public class Car implements Tranfertaction{
@Override
public void run() {
System.out.println("开车创死你");
}
}
//测试类main方法测试
public class Client {
public static void main(String[] args) {
CarHanlderWork carHanlderWork = new CarHanlderWork();
carHanlderWork.run();
}
}
组合或聚合实现静态代理:
/**
* 通过聚合或组合实现代理,该种代理称为静态代理:
* 定义一个类,内部持有被代理对象的一个引用,此处的引用最好使用被代理对象的父类
* 实现一个方法,在方法内部调用被代理对象的方法。并在调用前后加日志记录
*/
public class CarHanlerTime {
Transportation target;
public CarHanlerTime(Transportation target) {
this.target = target;
}
public void invoke() {
System.out.println("开车时间:" + System.currentTimeMillis());
target.run();
System.out.println("创死时间:" + System.currentTimeMillis());
}
}
//测试
public class Client {
public static void main(String[] args) {
Car car = new Car();
CarHanlerTime carHanlerTime = new CarHanlerTime(car);
carHanlerTime.invoke();
}
}
多个日志叠加,创建两个日志代理类,实现和Car一样的父类接口。
public class CarHanlerTime implements Transportation{
Transportation target;
public CarHanlerTime(Transportation target) {
this.target = target;
}
public void run() {
System.out.println("开车时间:" + System.currentTimeMillis());
target.run();
System.out.println("创死时间:" + System.currentTimeMillis());
}
}
public class CarHanlerWork2 implements Transportation {
Transportation target;
public CarHanlerWork2(Transportation target) {
this.target = target;
}
public void run() {
System.out.println("开车:" );
target.run();
System.out.println("熄火:" );
}
}
public class Client {
public static void main(String[] args) {
Car car = new Car();
CarHanlerTime carHanlerTime = new CarHanlerTime(car);
CarHanlerWork2 carHanlerWork2 = new CarHanlerWork2( carHanlerTime);
carHanlerTime.run();
}
}
三、动态代理
(一)动态代理
是在内存中生成代理对象的一种技术
无需手写代理类,也不会存在代码编译的过程。运用在内存中生产代理类的技术在JVM的运行区造一个代理对象,只需对需要修改的部分进行编辑。
(二)动态代理JDK使用
实际上就是在内存中生产一个对象,该对象实现了指定的目标对象的所有接口,代理对象和目标对象是兄弟关系。
jdk自带动态代理技术,需要使用一个静态方法来创建代理对象,它需要目标对象必须实现接口,生产的代理对象和原对象都实现相同的接口。
public class CarHanlerTime implements InvocationHandler {
Transportation target;
public CarHanlerTime(Transportation target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开车时间:" + System.currentTimeMillis());
target.run();
System.out.println("创死时间:" + System.currentTimeMillis());
return null;
}
}
//
public class Client {
public static void main(String[] args) {
Car car = new Car();
CarHanlerTime carHanlerTime = new CarHanlerTime(car);
Transportation instance = (Transportation) Proxy.newProxyInstance(Transportation.class.getClassLoader(),
new Class[]{Transportation.class}, carHanlerTime);
instance.run();
}
}
(三)动态代理简单实现,自己通过反射手写,并试图理解。
/**
* 使用动态代理实现日志记录
* 定义一个日志记录的代理类,并实现InvocationHandler接口,重写内部的invoke方法。加上要代理的逻辑
* 在该代理类中需要持有一个成员变量,该变量可以代表java中的任意对象.
*/
public class LogHandler implements InvocationHandler {
private Object target;
/**
* 该构造方法的作用:
* 用于接收被代理的对象。
* @param target
*/
public LogHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("启动");
//调用被代理对象target的指定方法method,该方法由生成的代理对象中的方法传入。
method.invoke(target);
System.out.println("熄火");
return null;
}
}
public class Client {
public static void main(String[] args) throws Exception {
Man man = new Man();
LogHandler handler = new LogHandler(man);
Person person = (Person) Proxy.newProxyInstance(Person.class, handler);
person.eat();
person.sleep();
}
}
public class Proxy {
public static Object newProxyInstance(Class infc, InvocationHandler handler) throws Exception {
String methodStr = "";
Method[] methods = infc.getMethods();
for (Method method : methods) {
methodStr += " public void " + method.getName() + "(){\n" +
" try{\n" +
//获取被代理对象要被执行的方法
" Method md = " + infc.getName() + ".class.getMethod(\"" + method.getName() + "\");\n" +
" h.invoke(this, md);\n" +
" }catch(Exception e) {}\n" +
" }\n";
}
String src =
"import com.proxy.Person;\n" +
"import com.proxy.InvocationHandler;\n" +
"import java.lang.reflect.Method;\n" +
"public class Proxy1 implements " + infc.getName() + "{\n" +
" private InvocationHandler h;\n" +
" public Proxy1(InvocationHandler h) {\n" +
" this.h = h;\n" +
" }\n" +
methodStr +
"}";
//此处文件需要写到某个盘下,不建议写道项目路径,因为不能及时生成文件,要等到程序跑完才能生成文件
//这样会导致反射去加载类时找不到生成的文件
String fileName = "D:/qf/src/Proxy1.java";//System.getProperty("user.dir")+"/Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//javac TimeHandler01.java
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable iterable = fileManager.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
task.call();
fileManager.close();
URL[] urls = new URL[]{new URL( "file:/D:/qf/src/")};
URLClassLoader classLoader = new URLClassLoader(urls);
Class clazz = classLoader.loadClass("Proxy1");
Constructor<?> constructor = clazz.getDeclaredConstructor(InvocationHandler.class);
Object obj = constructor.newInstance(handler);
return obj;
}
}
public interface InvocationHandler {
void invoke(Object o, Method m) throws Exception;
}
public class LogHandler implements InvocationHandler {
Object target;
public LogHandler(Object target) {
this.target = target;
}
@Override
public void invoke(Object o, Method m) throws Exception {
System.out.println("Log你好吗");
m.invoke(target);
System.out.println("Log哦哦哦哦哦");
}
}
public interface Person {
void eat();
void sleep();
}
public class Man implements Person {
@Override
public void eat() {
System.out.println("在吃饭-----");
}
@Override
public void sleep() {
System.out.println("在睡觉----");
}
}