设计模式之代理模式

代理模式的定义

代理模式的分类

静态代理

动态代理

JDK动态代理

Cglib动态代理


 

代理模式的定义

代理模式即给一个对象提供一个代理的对象,代理对象其实是目标对象(被代理对象)的一种增强和扩展。相当于生活中明星的经纪人、中介。

代理模式的分类

静态代理

1、定义一个抽象公共对象

/**
 * @author yms
 * @description:定义一个抽象公共对象,即一个公共接口,让目标类和代理类去实现
 * @date: 2021/1/8 18:38
 */
public interface IHaShiQiStore {

  void sellHaShiQi(String type);

}

2、目标类(被代理类)

/**
 * @author yms
 * @description:目标类
 * @date: 2021/1/8 18:42
 */
public class HaShiQiStore implements IHaShiQiStore{

  @Override
  public void sellHaShiQi(String type) {
    System.out.println("该商店出售"+type);
  }
}

3、代理类

/**
 * @author yms
 * @description:代理类
 * @date: 2021/1/8 18:43
 */
public class StaticProxy implements IHaShiQiStore{

  private IHaShiQiStore dogStore;

  public StaticProxy (IHaShiQiStore store){
    this.dogStore = store;
  }

  public void beforeSell(){
    System.out.println("进行售前咨询");
  }
  public void afterSell(){
    System.out.println("进行售后保养");
  }

  @Override
  public void sellHaShiQi(String type) {
    beforeSell();
    dogStore.sellHaShiQi(type);
    afterSell();
  }
}

4、测试

/**
 * @author yms
 * @description:测试
 * 静态代理的好处:编码相对简单
 * 静态代理的弊端:扩展性、可维护性较差,
 * 如果需要出售金毛,则需要重新创建一个新的公共接口、目标类及代理类,会造成很多重复代码
 * @date: 2021/1/8 18:50
 */
public class StaticProxyTest {

  public static void main(String[] args) {
    //创建一个目标类对象
    IHaShiQiStore target = new HaShiQiStore();
    //创建一个代理类对象
    IHaShiQiStore proxy = new StaticProxy(target);
    //代理对象负责完成宠物狗的出售
    proxy.sellHaShiQi("哈士奇");
  }

}

 

动态代理

动态代理下,我们的代理类不需要和被代理类实现同一个接口,即在设计代理类的时候不需要去关心要代理谁,而是在运行的时候才会去指定需要代理的对象。Spring AOP就是通过动态代理去实现的。动态代理又分为两种:JDK动态代理和Cglib动态代理。

JDK动态代理

1、抽象公共对象

/**
 * @author yms
 * @description:需要动态代理的接口
 * @date: 2021/1/9 10:48
 */
public interface IPetStore {

  void sellPet(String type);

}

2、被代理类

/**
 * @author yms
 * @description:实际被代理的类(目标类)
 * @date: 2021/1/9 10:50
 */
public class JdPetStore implements IPetStore{

  @Override
  public void sellPet(String type) {
    System.out.println("京东宠物店,出售宠物--->"+type);
  }
}

3、代理类(动态处理器)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author yms
 * @description:代理类
 * @date: 2021/1/9 10:51
 * JdkProxy 实现了 InvocationHandler 接口,并能实现方法调用从代理类到被代理类的分派转发
 * 其内部通常包含指向被代理类实例的引用,用于真正执行分派转发过来的方法调用.
 * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
 */
public class JdkProxy implements InvocationHandler {
  //被代理的真实对象
  private Object target;
  //构造方法,给要代理的真实对象赋初始值
  public JdkProxy (Object target){
    this.target = target;
  }

  public void beforeSell(){
    System.out.println("--------->这里负责售前,买之前做好心理准备");
  }

  public void afterSell(){
    System.out.println("--------->这里负责售后,专治各种不服");
  }
  /**
   * 所有动态代理类的方法调用,都会交给invoke()方法来处理
   * @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信息---->"+method);
    beforeSell();
    Object result = method.invoke(target, args);//通过反射调用类里面的实际方法
    afterSell();
    return result;
  }
}

4、测试

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * @author yms
 * @description:
 * @date: 2021/1/9 11:02
 */
public class JdkProxyTest {

  public static void main(String[] args) {
    //被代理对象
    IPetStore jd = new JdPetStore();
    //当前被代理对象的类加载器
    ClassLoader jdLoader = jd.getClass().getClassLoader();
    //当前被代理对象所实现的所有接口
    Class [] jdInterfaces = jd.getClass().getInterfaces();

    InvocationHandler handler = new JdkProxy(jd);
    //通过Proxy获取代理对象
    IPetStore proxyJD = (IPetStore) Proxy.newProxyInstance(jdLoader,jdInterfaces,handler);
    proxyJD.sellPet("哈士奇");
  }

}

Cglib动态代理

1、抽象公共对象

/**
 * @author yms
 * @description:目标接口
 * @date: 2021/1/9 23:08
 */
public interface IStar {

  void singASong();

}

2、 被代理类

/**
 * @author yms
 * @description:被代理类
 * @date: 2021/1/9 23:11
 */
public class StarImpl implements IStar{

  @Override
  public void singASong() {
    System.out.println("郑源开演唱会");
  }
}

3、代理类

/**
 * @author yms
 * @description:代理类
 * @date: 2021/1/9 23:14
 * cglib是一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法
 * 简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。
 * 但是如果被代理类被final修饰,那么它不可被继承,即不可被代理;
 * 同样,如果被代理类中存在final修饰的方法,那么该方法也不可被代理
 *
 */
public class CglibProxy implements MethodInterceptor {

  public void beforeSing(){
    System.out.println("主办方找到郑源的经纪人");
  }

  public void afterSing(){
    System.out.println("经纪人处理演唱会后的相关事宜");
  }

  /**
   * 代理方法
   * @param target  被代理类
   * @return  代理类
   */
  public Object createProxy(Object target){
    //创建一个动态代理类对象
    Enhancer enhancer = new Enhancer();
    //确定要代理的类,设置其父类
    enhancer.setSuperclass(target.getClass());
    //添加回调函数,即方法拦截处理器
    enhancer.setCallback(this);
    //返回创建的代理类
    return enhancer.create();

  }



  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
      throws Throwable {
    beforeSing();
    Object obj = methodProxy.invokeSuper(o,objects);
    afterSing();
    return obj;
  }
}

 4、测试

/**
 * @author yms
 * @description:
 * @date: 2021/1/9 23:38
 * 1、静态代理需要为每个目标类(被代理类)创建一个代理类,代理类需要和被代理类实现同一个接口,
 *   如果被代理类发生了改变,则代理类则需要同步进行改变,会造成很多重复代码,可维护性大大降低
 * 2、JDK的动态代理具有局限性,使用动态代理的对象必须实现一个或多个接口
 * 3、如果想代理没有实现接口的类,那么使用CGLIB动态代理即可
 * 4、Spring AOP基于动态代理实现,很好的对OOP进行了延伸和扩展
 */
public class CgProxyText {

  public static void main(String[] args) {
    //创建代理类对象
    CglibProxy proxy = new CglibProxy();
    //创建被代理类对象(目标对象)
    IStar star = new StarImpl();
    //获取扩展后的被代理类对象
    IStar strongStar = (IStar) proxy.createProxy(star);
    //执行被代理类的方法
    strongStar.singASong();
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值