代理模式要用定义的方式描述可能要写一大串,简单的描述一下把。比如说一个班级有40个学生,一个班上,一个老师,学生开学要交学费,不可能一个个学生跑到老师面前交学费吧。说大一点,全校学生要交学费,不可能所有人跑到校长面前交学费吧。这个时候代理模式孕育而生,班级中可以选取班长作为代理者收取班上学生的学费,然后上交给老师,然后老师可以做为学生的代理者将学费交到学校,这样一说是不是要简单理解一点了。
下面放个图,大家理解理解吧。
下面我将从两个demo来对静态代理和动态代理来进行总结学习。
首先静态代理的demo很好写,也很好理解。
首先创建Person接口
/**
* 创建Person接口
* @author Jet
*/
public interface Person {
void giveMoney();//上交学费
}
然后用学生类实例化Person接口
public class Student implements Person{
private String name;
public Student(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "上交学费10000");
}
}
然后写一个学生代理类,来代理学生完成交学费的任务。
/**
*学生代理类,实现了Person接口,保存一个学生实体,这样可以代理学生产生行为
*@author Jet
*/
public class StudentsProxy implements Person{
Student student;
//被代理的学生对象
public StudentsProxy(Person student){
//只代理学生对象
if(student.getClass() == Student.class){
this.student = (Student)student;
}
}
//代理上交班费,调用被代理学生的上交学费行为
@Override
public void giveMoney() {
student.giveMoney();
}
}
主类:
public class Main {
public static void main(String[] args) {
//被代理的学生Jet,他的学费由班长帮他上交
Person jet = new Student("jet");
//生成代理对象班长,把jet传给代理对象
Person monitor = new StudentsProxy(jet);
//实现被代理人的行为
monitor.giveMoney();
}
}
运行结果
当然在代理类中可以加入更多的逻辑来完善学生类的任务功能,比如说输出什么时候交的学费。
@Override
public void giveMoney() {
Date date = new Date();
System.out.println(date.toString());
student.giveMoney();
}
运行结果:
动态代理:
要是首先说动态代理的实现和概念,我想可能是个挺难理解的东西,所以我们先来看一个demo。
首先还是要先创建Person接口
/**
* 创建Person接口
* @author Jet
*/
public interface Person {
void giveMoney();//上交学费
}
学生类实现Person接口
public class Student implements Person{
private String name;
public Student(String name){
this.name = name;
}
@Override
public void giveMoney() {
try {
Thread.sleep(1000);
//假设上交学费时间花了1s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "上交学费10000");
}
}
时间类记录上交学费方法执行时间
public class MonitorUtil {
private static ThreadLocal<Long> t1 = new ThreadLocal<>();
/**
* ThreadLocal是线程变量,是一个以ThreadLocal对象为键、任意对象为值得存储结构。这个结构被附带在线程上,
* 也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值
*/
public static void start(){
t1.set(System.currentTimeMillis());
}
//结束时打印耗时
public static void finish(String methodName){
long finishTime = System.currentTimeMillis();
System.out.println(methodName+"方法耗时"+(finishTime - t1.get()) + "ms");
}
}
创建StuInvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StuInvocationHandler<T> implements InvocationHandler {
//invocationHandler持有的被代理对象
T target;
public StuInvocationHandler(T target){
this.target = target;
}
/**
* @param proxy 代表动态代理的对象
* @param method 代表正在执行的方法
* @param args 代表调用目标方法时传入的实参
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
MonitorUtil.start();//在代理过程中插入监测方法,计算方法耗时
Object result = method.invoke(target,args);
MonitorUtil.finish(method.getName());
return null;
}
}
创建动态代理对象:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
//被代理的学生Jet,这个对象是被代理的对象
Person jet = new Student("jet");
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler studentHandler = new StuInvocationHandler<Person>(jet);
//创建一个代理对象stuProxy来代理jet,代理对象的每个执行方法都会替换执行Invocation中invoke方法
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class},studentHandler);
//代理执行上交班费的方法
stuProxy.giveMoney();
}
}
最后将Proxy.newProxyInstance的源码附上:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
那么动态代理是什么呢?
(动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组);然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员。 初始化之后将对象返回给调用的客户端。这样客户端拿到的就是一个实现你所有的接口的Proxy对象。)
以上就是我对Java设计模式静态代理和动态代理的总结和理解,如果以后会有更深的学习还会补上。