设计模式——Proxy代理模式

设计模式——Proxy代理模式

Proxy代理模式

 为其他对象提供一种代理,以控制这个对象的访问。代理对象起到中介作用,可以去掉功能服务或增加额外的服务。

几种常见的代理模式

远程代理:为不同地理的对象提供局域网代表对象。

虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。

保护代理:控制用户的访问权限。

智能引用代理:提供对目标对象额外服务。

 

静态代理

代理和被代理对象在代理之前是确定的,他们都实现相同的接口或者继承相同的抽象类。代理类可以继承或聚合被代理类,以便于扩充和删减功能。(有点像装饰器模式)

举栗:

Moveable.java

public interface Moveable {
  
void move();
}

Car.java

接口的实现类。

public class Car implementsMoveable {
  
@Override
  
public void move() {
     
try {
         Thread.sleep(
new Random().nextInt(1000));
        
System.out.println("汽车行驶中...");
     
} catch (InterruptedException e) {
         e.printStackTrace()
;
     
}
   }
}

CarLogProxy.java

记录日志代理,实现Moveable接口

public class CarLogProxy implements Moveable {

  
public CarLogProxy(Moveable m) {
     
super();
      this
.m = m;
  
}

  
private Moveable m;

  
@Override
  
public void move() {
      System.
out.println("日志开始....");
     
m.move();
     
System.out.println("日志结束....");
  
}

}

CarTimeProxy.java

记录行驶时间代理,实现Moveable接口。

public class CarTimeProxy implements Moveable {

  
public CarTimeProxy(Moveable m) {
     
super();
      this
.m = m;
  
}

  
private Moveable m;

  
@Override
  
public void move() {
     
long startTime = System.currentTimeMillis();
     
System.out.println("汽车开始行驶....");
     
m.move();
      long
endTime = System.currentTimeMillis();
     
System.out.println("汽车结束行驶....  汽车行驶时间:"
           
+ (endTime - startTime) + "毫秒!");
  
}

}

Test.java

使用聚合的方式、实现同样的接口来实现功能的扩充。

输出:

汽车开始行驶....

日志开始....

汽车行驶中...

日志结束....

汽车结束行驶....  汽车行驶时间:147毫秒!

public class Test {

  
public static void main(String[] args) {
      Car car =
new Car();
     
CarLogProxy clp = new CarLogProxy(car);
     
CarTimeProxy ctp = new CarTimeProxy(clp);
     
ctp.move();
  
}

}

 

 

动态代理

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

1.     Interface InvocationHandler:该接口仅定义了一个方法

public object invoke(Object obj, Method method, Object[] args)在代理实例上处理方法调用并返回结果。第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

2.     Proxy:该类即为动态代理类

static ObjectnewProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明过的方法)。

 

动态代理实现步骤:

1.     创建一个实现接口InvocationHandler的类,必须实现invoke方法

2.     创建被代理的类以及接口

3.     调用Proxy的静态方法newProxyInstance创建一个代理类

4.     通过代理调用方法。

上面的栗子稍作修改:

Moveable.java

这里再多声明一个方法fun,用来测试

public interface Moveable {
  
void move();
   void
fun(String s);
}

Car.java

Moveable接口的一个实现类

public class Car implementsMoveable {

  
@Override
  
public void move() {
     
try {
         Thread.sleep(
new Random().nextInt(1000));
        
System.out.println("汽车行驶中...");
     
} catch (InterruptedException e) {
         e.printStackTrace()
;
     
}
   }

  
@Override
  
public void fun(String s) {
      System.
out.println("fun方法+"+s);
  
}

}

TimeHandler.java

实现InvocationHandler接口,实现invoke方法。该方法在代理实例上处理方法调用并返回结果,被代理类的任何一个方法的调用都会被该代理处理,下面使用接口中的两个方法进行测试。

public class TimeHandler implements InvocationHandler {

  
public TimeHandler(Object target) {
     
super();
      this
.target = target;
  
}

  
private Object target;

  
/*
    *
参数:
    * proxy 
代理对象
    * method 
被代理对象的方法
    * args
方法的参数
    *
    *
返回值:
    * Object 
方法的返回值
    * */
  
@Override
  
public Object invoke(Object proxy, Method method, Object[] args)
        
throws Throwable {
     
long starttime = System.currentTimeMillis();
     
System.out.println("汽车开始行驶....");
      if
(args!=null)
          System.
out.println(method.getName()+args.length);
      else
         
System.out.println(method.getName());
     
method.invoke(target,args);
      long
endtime = System.currentTimeMillis();
     
System.out.println("汽车结束行驶....  汽车行驶时间:"
           
+ (endtime - starttime) + "毫秒!");
      return null;
  
}

}

Test.java

测试类,输出:

汽车开始行驶....

move

汽车行驶中...

汽车结束行驶....  汽车行驶时间:18毫秒!

汽车开始行驶....

fun1

fun...123

汽车结束行驶....  汽车行驶时间:0毫秒!

从上面的输出可以看出代理类可以实现并修改被代理类的一些功能,并且每个方法都是通过invoke来通过反射机制执行。方法调用的对象,方法自身的Method对象,方法的参数,这些都可以获得并进行处理。

 

public class Test {

  
/**
    * JDK
动态代理测试类
   
*/
  
public static void main(String[] args) {
      Car car =
new Car();
     
InvocationHandler h = new TimeHandler(car);
     
Class<?> cls = car.getClass();
     
/**
       * loader 
类加载器
       
* interfaces  实现接口
      
* h InvocationHandler
       */
     
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
           
cls.getInterfaces(), h);
     
m.move();
     
m.fun("123");
  
}

}

若是添加多层代理,可以在测试类中继续编写,当然这里要写一个LogHandler的实现类,这里就不贴代码了,和TimeHandler类似。

//多添加一层代理
InvocationHandlerlogHandler = new LogHandler(m);
Moveable m2=(Moveable) Proxy.newProxyInstance(cls.getClassLoader(),
             
cls.getInterfaces(), logHandler);
m2.move();

 

也可以使用cglib实现动态代理,与JDK动态代理区别:

JDK动态代理只能代理实现了接口的类,而cglib是针对类来实现代理的,对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用(不能对final修饰的类进行代理)。

 

总结

简单来说,动态代理实现过程就是定义接口,定义代理类,拿到代理类的实例,通过代理类的实例调用被代理类的一些功能。这其中涉及到根据反射机制生成java代码,编译成字节码,加载到内存,调用等。大概理解一下整体思路,对应上面的例子加深理解,必要时可以阅读相关源码,查看实现细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值