java代理实现

一、代理模式

给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问.

按照代理对象的创建时期,可分为静态代理和动态代理。
静态代理:静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
动态代理:动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

二、静态代理

举例:我想卖车,但我很忙,不想被电话骚扰,于是交给二手车交易所来帮我卖车

卖车子接口

interface SaleCar{
  void sale();
}

张三真正卖车子的实现类(委托类

class ZhangSanTrade implements SaleCar{
  @Override
  public void sale() {
    System.out.println("zhangsan sale his car");
  }
}

二手车交易类(代理类

class CarTradeProxy implements SaleCar{

  private ZhangSanTrade owner;

  public CarTradeProxy(ZhangSanTrade owner){
    this.owner=owner;
  }

  @Override
  public void sale() {
    System.out.println("proxy add price");
    owner.sale();
  }
}

测试
在这里插入图片描述

疑问:代理类和委托类差别不大,直接创建委托类调用sale方法不就可以了吗?
解答:代理类在真正调用委托类的方法之前做了中间加价的操作。即代理模式实现在委托类的基础上增加了额外的逻辑操作

需求增加:
我想用卖车的钱加自己的一些存款买个房子,自己也不想东奔西跑,于是把买房委托房产中介

在定义一个买房的接口

interface BuyHouse{
  void buy();
}

重写委托类,实现卖车和买房两个接口

class ZhangSanTrade implements SaleCar,BuyHouse{
  @Override
  public void sale() {
    System.out.println("zhangsan sale his car");
  }

  @Override
  public void buy() {
    System.out.println("zhangsan buy house");
  }
}

可以看到,我现在既要卖车,也要买房子
在创建一个买房子的中介代理类

class HouseTradeProxy implements BuyHouse{

  private ZhangSanTrade owner;

  public HouseTradeProxy(ZhangSanTrade owner){
    this.owner=owner;
  }

  @Override
  public void buy() {
    System.out.println("proxy add price");
    owner.buy();
  }
}

测试类

  public static void main(String[] args) {
    //委托类
    ZhangSanTrade zhangSanSaleCar=new ZhangSanTrade();
    //代理类
    CarTradeProxy carTradeProxy=new CarTradeProxy(zhangSanSaleCar);
    carTradeProxy.sale();
    System.out.println("------------------------------");
    HouseTradeProxy houseTradeProxy=new HouseTradeProxy(zhangSanSaleCar);
    houseTradeProxy.buy();
  }

优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:

  • 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
  • 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。

通过静态代理的方式,可以完美解决我们的问题,但当越来越多的委托类需要代理,而且代理做的工作又一样,会多出很多的代理类。此时想,我们可以只做一次,代理一类委托类,此时动态代理应运而生,它可以只定义一次就能为一类委托类做代理

三、动态代理

动态代理常见JDK 动态代理与 CGLIB 动态代理

区别:

  • Jdk动态代理:利用拦截器(必须实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
  • Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来进行代理
    因此:
    如果想要实现JDK动态代理那么代理类必须实现接口,否则不能使用;
    如果想要使用CGlib动态代理,那么代理类不能使用final修饰类和方法;

使用场景:
AOP 的实现原理、RPC远程调用、Java 注解对象获取、日志框架、全局性异常处理、事务处理

1 JDK动态代理实现

UserService接口

public interface UserService {
  void addUser();
  void updateUser(String str);
}

UserServiceImpl实现类

public class UserServiceImpl implements UserService{

  @Override
  public void addUser() {
    System.out.println("添加用户");
  }

  @Override
  public void updateUser(String str) {
    System.out.println("更新用户信息" + str);
  }
}

UserProxy代理类,实现InvocationHandler接口重写invoke方法

public class UserProxy implements InvocationHandler {

  private Object target;

  public UserProxy(Object target) {
    this.target = target;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    Object res = method.invoke(target, args);

    System.out.println("记录日志");

    return res;
  }
}

测试 ,实现了增强,打印出了日志
在这里插入图片描述

Proxy.newProxyInstance 方法得到的也是 UserService 的实现类对象,那么其实这是一种基于接口的动态代理。也叫做 JDK 动态代理

2 CGlib动态代理

JDK 动态代理是基于接口的代理,而 CGLIB 动态代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 ,也就是说 CGLIB 动态代理采用类继承 -> 方法重写的方式进行的,下面我们先来看一下 CGLIB 动态代理的结构。

在这里插入图片描述
如上图所示,代理类继承于目标类,每次调用代理类的方法都会在拦截器中进行拦截,拦截器中再会调用目标类的方法。

CGlib需要导入Jar包,那么我用SpringBoot直接导入依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

UserServiceImpl被代理类

public class UserServiceImpl implements UserService{

  @Override
  public void addUser() {
    System.out.println("添加用户");
  }

  @Override
  public void updateUser(String str) {
    System.out.println("更新用户信息" + str);
  }
}

UserServiceCGlib代理

public class UserServiceCGlib implements MethodInterceptor {

  private Object target;

  public UserServiceCGlib() {
  }

  public UserServiceCGlib(Object target) {
    this.target = target;
  }

  //返回一个代理对象:    是 target对象的代理对象
  public Object getProxyInstance() {
    //1. 创建一个工具类
    Enhancer enhancer = new Enhancer();
    //2. 设置父类
    enhancer.setSuperclass(target.getClass());
    //3. 设置回调函数
    enhancer.setCallback(this);
    //4. 创建子类对象,即代理对象
    return enhancer.create();
  }


  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
      throws Throwable {
    System.out.println("增强开始~~~");
    Object result = methodProxy.invokeSuper(o, objects);
    System.out.println("增强结束~~~");
    return result;
  }
}

测试类
在这里插入图片描述
注:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

总结:

  1. 如果加入容器的目标对象有实现接口,用JDK代理
  2. 如果目标对象没有实现接口,用Cglib代理
  3. 如果目标对象实现了接口,且强制使用cglib代理,则会使用cglib代理。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代理模式是一种常用的设计模式,其主要作用是为其他对象提供一种代理以控制对这个对象的访问。代理模式Java 中可以通过接口实现,也可以通过继承实现。下面分别介绍这两种实现方式。 1. 接口实现代理模式 接口实现代理模式需要定义一个接口和一个代理类,代理实现接口并持有一个接口的引用,通过代理类来间接访问目标对象。 示例代码如下: ```java // 定义接口 public interface Subject { void doSomething(); } // 目标对象 public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something"); } } // 代理类 public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void doSomething() { System.out.println("Before realSubject do something"); realSubject.doSomething(); System.out.println("After realSubject do something"); } } // 测试 public class Test { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Proxy proxy = new Proxy(realSubject); proxy.doSomething(); } } ``` 运行结果: ``` Before realSubject do something RealSubject do something After realSubject do something ``` 2. 继承实现代理模式 继承实现代理模式需要定义一个目标对象和一个代理对象,代理对象继承目标对象并重写目标对象的方法,在方法中间接访问目标对象。 示例代码如下: ```java // 目标对象 public class RealSubject { public void doSomething() { System.out.println("RealSubject do something"); } } // 代理对象 public class Proxy extends RealSubject { @Override public void doSomething() { System.out.println("Before realSubject do something"); super.doSomething(); System.out.println("After realSubject do something"); } } // 测试 public class Test { public static void main(String[] args) { Proxy proxy = new Proxy(); proxy.doSomething(); } } ``` 运行结果: ``` Before realSubject do something RealSubject do something After realSubject do something ``` 无论是接口实现还是继承实现代理模式的核心是代理类和目标对象的分离,通过代理类来控制对目标对象的访问,可以在不改变目标对象的情况下增加或修改一些额外的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值