代理模式
根据创建代理类的创建方式和时间不同可以分为:
1、静态代理 2、动态代理
代理模式的特征是什么?
代理类与委托类有相同的接口,代理类主要负责为委托类预处理事件以及其它消息。
代理类与委托类之间的联系
一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法。
1、静态代理
静态代理是什么
静态代理:编译时就将接口,代理类确定下来。在程序运行前就生成代理类的.class文件。
一个简单的静态代理实现
假如我给一个同学钱,让同学帮我写作业。这里,同学就是代理我写作业。
同学就是我的代理,程序编写的步骤如下:
1,创建一个Student接口。这个接口就是我(委托)和同学(代理)的公共接口,我们都有写作业的行为。这样,我的作业就可以通过同学来代理执行。
2、StudentImplements类(委托类)实现Student接口。
3、StudentProxy类(代理类)也实现Student这个接口。同时持有一个StudentImplements对象用来执行写作业这一行为。
4、创建代理模式的测试类ProxyTest。
Student接口:
/**
* 创建Student接口
* @author zzx
* */
public interface Student {
void doHomework();
}
StudentImplements类:
public class StudentImplements implements Student{
private String name;
public StudentImplements() {
}
public StudentImplements(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void doHomework() {
System.out.println(name+"做作业");
}
}
StudentProxy类:
/**
* 代理类实现Student接口,保存StudentImplements实体,这样可以代理StudentImplements产生的行为
* @author zzx
* */
public class StudentProxy implements Student{
//被代理的对象
StudentImplements stu;
public StudentProxy(Student stu) {
//通过判断只代理StudentImplements对象
if(stu.getClass()==StudentImplements.class){
this.stu= (StudentImplements) stu;
}
}
@Override
public void doHomework() {
System.out.println("给我钱");
stu.doHomework();
}
}
ProxyTest:
public class ProxyTest {
public static void main(String[] args) {
//被代理的学生我,我的作业有代理对象同学完成
Student me=new StudentImplements("zzx");
Student student=new StudentProxy(me);
student.doHomework();
}
}
在代理类中重写的方法中,我们可以做一些额外的处理。就是在Spring中的面向切面编程(AOP),我们能在一个切点执行一些操作。
2、动态代理
动态代理是什么
代理类在程序运行时创建的代理方式。
动态代理与静态代理的区别
动态代理的代理类是在Java代码中的“指示”动态生成的,相比于静态代理可以更方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。
一个动态代理实现过程
字Java的Java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成动态代理类和动态代理对象。
1、创建一个InvocationHandler对象
2、使用Proxy类的getProxyClass方法生成一个动态代理类stuProxyClass
3、获得stuProxyClass中一个带InvocationHandler参数的构造器constructor
4、通过构造器constructor来创建一个动态实例stuProxy
上面的4个步骤可以通过Proxy类newProxyInstances方法简化。
一个例子
张三上交班费由班长代缴:
MonitorUtil:
public class MonitorUtil {
private static ThreadLocal<Long> time= new ThreadLocal<>();
public static void setTime(ThreadLocal<Long> time) {
MonitorUtil.time = time;
}
public static void start(){
time.set(System.currentTimeMillis());
}
//结束时打印消耗
public static void finish(String methodName){
long finishTime =System.currentTimeMillis();
System.out.println(methodName+"方法耗时"+(finishTime-time.get())+"ms");
}
}
Person接口:
/**
* 创建Person接口
* @author zzx
* */
public interface Person {
//上交班费
void giveMoney();
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//创建一个实例对象,这个对象是被代理的对象
Person zhangSan= new Student("张三");
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler= new StuInvocationHandler<>(zhangSan);
//创建一个代理对象stuProxy来代理zhangSan,代理对象的每个执行方法都会替换
//执行Invocation中的invoke方法
Person stuProxy=(Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class},stuHandler);
//代理执行上交班费的方法
stuProxy.giveMoney();
}
}
Student
public class Student implements Person{
private String name;
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(String name) {
this.name = name;
}
@Override
public void giveMoney(){
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(name+"上交班费50元");
}
}
StuInvocationHanlder:
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;
}
/**
* proxy:代表动态代理对象9*
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参*/
@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 result;
}
}
如果想进行深究动态代理原理
:添加链接描述