设计模式-代理模式

定义

  • 特征是代理类与委托类有同样的接口

  • 代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

  • 代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

  • 我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途

用法

静态代理

  • 通过继承实现
通过继承被代理对象,重写被代理方法,可以对其进行代理。
优点:被代理类无需实现接口
缺点:只能代理这个类,要想代理其他类,要想代理其他类需要写新的代理方法。
 
public class Tank{
    public void move() {
        System.out.println("Tank moving cla....");
    }
}
 
class ProxyTank extends Tank{
    @Override
    public void move() {
        System.out.println("方法执行前...");
        super.move();
        System.out.println("方法执行后...");
    }
}
  • 通过组合实现
定义一个 Movable 接口被代理类需要和代理类都需要实现该接口。(接口在这里的目的就是起一个规范作用保证被代理类和代理类都实现了move()方法)。代理类需要将该接口作为属性,实例化时需要传入该接口的对象,这样该代理类就可以实现代理所有实现Movable的类了。
优点:可以代理所有实现接口的类。
缺点:被代理的类必须实现接口。
JDK动态代理就是采用的这种方式实现的。同样的代理类是由JDK自动帮我们在内存生成的。
 
public class Tank implements Movable{
    @Override
    public void move() {
        System.out.println("Tank moving cla....");
    }
 
    public static void main(String[] args) {
        Tank tank = new Tank();
        new LogProxy(tank).move();
    }
}
 
class LogProxy implements Movable{
    private Movable movable;
    public LogProxy(Movable movable) {
        this.movable = movable;
    }
    @Override
    public void move() {
        System.out.println("方法执行前....");
        movable.move();
        System.out.println("方法执行后....");
    }
}
interface Movable {
    void move();
}
 

缺点:静态代理实现方式很直观也很简单,但其缺点是代理对象必须提前写出,如果接口层发生了变化,代理对象的代码也要进行维护。如果能在运行时动态地写出代理对象,不但减少了一大批代理类的代码,也少了不断维护的烦恼,不过运行时的效率必定受到影响。

 动态代理

定义

静态代理与动态代理的主要区别在于:

  • 静态代理在编译时已经实现,编译后会生成对应的实际的class文件
  • 动态代理是在运行时产生的,是在运行时动态的生成类字节码,并加载到了JVM中
  • 动态代理实际上用的就是反射的机制

而实现动态代理的方式又可分为两种:

  • JDK动态代理
  • CGLIB动态代理

JDK动态代理

public interface ISinger {
    void sing();
}
 
 /**
  *  目标对象实现了某一接口
  */
public class Singer implements ISinger{
    public void sing(){
        System.out.println("唱一首歌");
    }  
}
 
由于java底层封装了实现细节(之后会详细讲),所以代码非常简单,格式也基本上固定。
调用Proxy类的静态方法newProxyInstance即可,该方法会返回代理类对象
static Object newProxyInstance(ClassLoader loader
                               ,Class<?>[] interfaces
                               ,InvocationHandler h)
接收的三个参数依次为:
ClassLoader loader:指定当前目标对象使用类加载器,写法固定
Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类
 
public class Test{
     public static void main(String[] args) {
         Singer target = new Singer();
         ISinger proxy  = (ISinger) Proxy.newProxyInstance(
                 target.getClass().getClassLoader(),
                 target.getClass().getInterfaces(),
                 new InvocationHandler() {
                     @Override
                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                         System.out.println("向观众问好");
                         //执行目标对象方法
                         Object returnValue = method.invoke(target, args);
                         System.out.println("谢谢大家");
                         return returnValue;
                     }
                 });
         proxy.sing();
     }
 }

缺点: 目标对象必须实现一个或多个接口,假如没有,则可以使用Cglib代理。

cglib动态代理

  • 需要引入cglib的jar文件,由于Spring的核心包中已经包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
  • 目标类不能为final
  • 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
/**
 * 目标对象,没有实现任何接口
 */
public class Singer{
 
    public void sing() {
        System.out.println("唱一首歌");
    }
}
 
 
 /**
  * Cglib子类代理工厂
  */
 public class ProxyFactory implements MethodInterceptor{
     // 维护目标对象
     private Object target;
 
     public ProxyFactory(Object target) {
         this.target = target;
     }
 
     // 给目标对象创建一个代理对象
     public Object getProxyInstance(){
         //1.工具类
         Enhancer en = new Enhancer();
         //2.设置父类
         en.setSuperclass(target.getClass());
         //3.设置回调函数
         en.setCallback(this);
         //4.创建子类(代理对象)
         return en.create();
     }
 
     @Override
     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
         System.out.println("向观众问好");
         //执行目标对象的方法
         Object returnValue = method.invoke(target, args);
         System.out.println("谢谢大家");
         return returnValue;
     }
 }
 
 /**
  * 测试类
  */
 public class Test{
     public static void main(String[] args){
         //目标对象
         Singer target = new Singer();
         //代理对象
         Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();
         //执行代理对象的方法
         proxy.sing();
     }
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值