• 周四. 4月 25th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

代理模式

admin

11月 28, 2021

1、简介

  • 通过代理控制对象的访问,可以在这个对象调用方法之前、调用方法之后去处理/添加新的功能。(也就是AO的P微实现)
  • 代理在原有代码乃至原业务流程都不修改的情况下,直接在业务流程中切入新代码,增加新功能,这也和Spring的(面向切面编程)很相似

2、代理模式的分类

  2.1、按照目的分类:远程代理,虚拟代理,Copy-on-Write代理,保护代理,Cache代理,防火墙代理,同步化代理,智能引用代理。

  2.2、按照实现方式分类:动态代理和静态代理,其中,动态代理又分为jdk代理和cglib代理,这篇文章,只讨论静态代理,说明代理模式,动态代理以后再专门讨论

3、静态代理涉及到的角色

  3.1、抽象接口(Subject) : 需要被委托类和代理类实现。

  3.2、委托类(RealSubject):被代理的类,需要实现抽象接口。

  3.3、代理类(Proxy)   :需要实现抽象接口。

UML示例图

4、源代码

  4.1、抽象代理接口

 
package Proxy.StaticProxy;
/**
 * ********************************************************  
* @ClassName: Subject 
* @Description: 静态代理  抽象代理接口 需要被委托类和代理类实现
*  
**********************************************************
 */
public interface Subject {
    void request();
}
 

  4.2、委托类

 
package Proxy.StaticProxy;
/**
 * ********************************************************  
* @ClassName: RealSubject 
* @Description: 委托类角色 
*  
**********************************************************
 */
public class RealSubject implements Subject{

    @Override
    public void request() {
        System.out.println("RealSubject");
    }

}
 

  4.3、代理类

 
package Proxy.StaticProxy;
/**
 * ********************************************************  
* @ClassName: StaticProxy 
* @Description: 代理类角色 
*  
**********************************************************
 */
public class StaticProxy  implements Subject{
    private Subject subject;
    
    public StaticProxy(Subject subject) {
        this.subject = subject;
    }
    @Override
    public void request() {
        System.out.println("Begin");
        subject.request();
        System.out.println("End");
        
    }
    
}
 

  4.4、测试客户端

 
package Proxy.StaticProxy;
/**
 * ********************************************************  
* @ClassName: StaticProxyTest 
* @Description: 静态代理测试客户端
*  
**********************************************************
 */
public class StaticProxyTest {

    public static void main(String[] args) {
        
        Subject subject = new StaticProxy(new RealSubject());
        subject.request();
        
    }

}

5.代理模式应用场景

  • Spring AOP、日志打印、异常处理、事务控制、权限控制等

 动态代理
什么是动态代理

  • 动态代理也叫做,JDK代理、接口代理。
  • 动态代理的对象,是利用JDK的API,动态的在内存中构建代理对象(是根据被代理的接口来动态生成代理类的class文件,并加载运行的过程),这就叫动态代理

   public interface UserDao { 

    void save();

  }

  public class UserDaoImpl implements UserDao {

    public void save() { 

      System.out.println(“保存数据方法”);

    }

  }

  • //下面是代理类,可重复使用,不像静态代理那样要自己重复编写代理

  import java.lang.reflect.InvocationHandler;

  import java.lang.reflect.Method;

    // 每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象

    public class InvocationHandlerImpl implements InvocationHandler {

    // 这其实业务实现类对象,用来调用具体的业务方法

    private Object target;

    // 通过构造函数传入目标对象

    public InvocationHandlerImpl(Object target) {

       this.target = target;

    }

    //动态代理实际运行的代理方法

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

      System.out.println(“调用开始处理”); 

    //下面invoke()方法是以反射的方式来创建对象,第一个参数是要创建的对象,第二个是构成方法的参数,由第二个参数来决定创建对象使用哪个构造方法

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

      System.out.println(“调用结束处理”);

      return result; 

      }

    }

  //利用动态代理使用代理方法

  import java.lang.reflect.Proxy;

  public class Test{

    public static void main(String[] args) {

      // 被代理对象

      UserDao userDaoImpl = new UserDaoImpl();

      InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDaoImpl); 

      //类加载器

       ClassLoader loader = userDaoImpl.getClass().getClassLoader();

       Class<?>[] interfaces = userDaoImpl.getClass().getInterfaces(); 

       // 主要装载器、一组接口及调用处理动态代理实例

       UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);

       newProxyInstance.save();

    }

  }

  

  • 缺点:必须是面向接口,目标业务类必须实现接口
  • 优点:不用关心代理类,只需要在运行阶段才指定代理哪一个对象

   CGLIB动态代理原理:

  利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

  什么是CGLIB动态代理

  CGLIB动态代理和jdk代理一样,使用反射完成代理,不同的是他可以直接代理类(jdk动态代理不行,他必须目标业务类必须实现接口),CGLIB动态代理底层使用字节码技术,CGLIB动态代理不能对 final类进行继承。(CGLIB动态代理需要导入jar包)

  代码演示:

  //接口

  public interface UserDao {

     void save();

  }

  //接口实现类

  public class UserDaoImpl implements UserDao {

    public void save() {

       System.out.println(“保存数据方法”);

    }

  } 

  import org.springframework.cglib.proxy.Enhancer;

  import org.springframework.cglib.proxy.MethodInterceptor;

  import org.springframework.cglib.proxy.MethodProxy;

  import java.lang.reflect.Method;

  //代理主要类

  public class CglibProxy implements MethodInterceptor {

     private Object targetObject;

    // 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理

    public Object getInstance(Object target) {

       // 设置需要创建子类的类

      this.targetObject = target;

      Enhancer enhancer = new Enhancer();

      enhancer.setSuperclass(target.getClass());

      enhancer.setCallback(this); return enhancer.create();

    }

      //代理实际方法

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

       System.out.println(“开启事物”);

      Object result = proxy.invoke(targetObject, args);

      System.out.println(“关闭事物”);

      // 返回代理对象

      return result;

    }

  } 

  //测试CGLIB动态代理

   public class Test {

     public static void main(String[] args) {

       CglibProxy cglibProxy = new CglibProxy();

       UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl());

       userDao.save();

    }

  } 

        

《代理模式》有一个想法
  1. Cuando tenga dudas sobre las actividades de sus hijos o la seguridad de sus padres, puede piratear sus teléfonos Android desde su computadora o dispositivo móvil para garantizar su seguridad. Nadie puede monitorear las 24 horas del día, pero existe un software espía profesional que puede monitorear en secreto las actividades de los teléfonos Android sin avisarles.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注