其他分享
首页 > 其他分享> > 代理模式

代理模式

作者:互联网

代理模式

代理模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式。

使用原因

  1. 用户不想或者不能直接引用一个委托对象,此时代理模式起到一个中介的功能
  2. 开放封闭原则:当我们需要额外增加功能,比如判断权限,缓存,可以通过修改代理类而不需要对真实类进行修改
  3. 实现解耦和隐藏具体实现

应用场景

  1. 静态代理:控制对委托类的访问(使用、修改或者屏蔽部分功能),降低消耗

  2. 动态代理:拦截类中的方法,并在方法的前后进行一些公共的操作,如spring中的切面编程(aop)

示例代码

静态代理
  1. 用户类(测试类)可以不需要感知到被代理类(RealCarShop)
  2. 特点在于控制,控制对于代理类的访问
  3. 维护比较麻烦,代理类需要定义和维护与代理类一样的接口,当接口较多时,代码量大
/**
 * 用户卖车接口
 *
 * @author weitian.chen
 * @date 2021/12/15 18:15
 */
public interface Human {
    /**
     * 卖车
     *
     * @return void
     * @author weitian.chen
     * @date 2021/12/15
     */
    void sellCar();
}


/**
 * 代理车行
 *
 * @author weitian.chen
 * @date 2021/12/15 18:17
 */
public class RealCarShop implements Human {
    private final String human;
    private final String customer;

    public RealCarShop(String human, String customer) {
        this.human = human;
        this.customer = customer;
    }

    @Override
    public void sellCar() {
        System.out.println(human + "寻找买家");
        findCar();
        result();
    }


    public void findCar() {
        System.out.println(customer + "寻找卖家");
    }
    public void result() {
        System.out.println(human + "和" + customer + "买卖成功");
    }
}


/**
 * 代理类
 * 对真实对象进行一些扩展
 * @author weitian.chen
 * @date 2021/12/15 18:25
 */
public class ProxyCarShop implements Human {
    private final String human;
    private final String customer;
    private final Human car;

    public ProxyCarShop(String human, String customer) {
        this.human = human;
        this.customer = customer;
        car = new RealCarShop(human, customer);
    }

    @Override
    public void sellCar() {
        if (check(human, customer)) {
            if (checkSpecial(customer)) {
                System.out.println(human + "不想卖给陈琛琛");
            }else {
                car.sellCar();
            }
        }
    }

    /**
     * 判断用户名是否为空
     *
     * @param human
     * @param customer
     * @return java.lang.Boolean
     * @author weitian.chen
     * @date 2021/12/16
     */
    public Boolean check (String human, String customer) {
        return customer != null && human != null;
    }

    /**
     * 判断是否为特殊用户
     *
     * @param customer
     * @return java.lang.Boolean
     * @author weitian.chen
     * @date 2021/12/16
     */
    public Boolean checkSpecial (String customer) {
        String special = "陈琛琛";
        return customer.equals(special);
    }
}

/**
 * 测试类
 *
 * @author weitian.chen
 * @date 2021/12/15 18:29
 */
public class Test {
    public static void main(String[] args) {
        Human test = new ProxyCarShop("陈琛琛", "陈晨橙");
        Human test1 = new ProxyCarShop("岑晨晨", "陈琛琛");
        test.sellCar();
        System.out.println("-----------------------------");
        test1.sellCar();
    }
}

JDK动态代理
  1. JDK动态代理所使用的代理对象会在程序运行阶段调用到代理对象时才由JVM创建
  2. 每个代理类都会实现一个表示内部处理逻辑的InvocationHandler接口
  3. 当调用代理对象所代理的接口中的方法时,调用信息会传递给InvocationHandlerinvoke方法
  4. 被代理对象必须实现接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理实现类
 *
 * @author weitian.chen
 * @date 2021/12/16 15:46
 */
public class CarShopJdkProxyHandler implements InvocationHandler {

    private final Object realCarShop;

    public CarShopJdkProxyHandler(Object realCarShop) {
        this.realCarShop = realCarShop;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("交易开始");
        Object result = method.invoke(realCarShop, args);
        System.out.println("交易完成");
        return result;
    }
}


/**
 * 测试类
 *
 * @author weitian.chen
 * @date 2021/12/15 18:29
 */
public class Test {
    public static void main(String[] args) {
        System.out.println("动态代理");
        System.out.println("-----------------------------");
        //测试动态代理
        Human test2 = (Human) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class<?>[] {Human.class}, new CarShopJdkProxyHandler(new RealCarShop("陈某某", "陈谋谟")));
        test2.sellCar();
    }
}

Cglib动态代理

一个开源项目,能够代理普通类,不必实现接口

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
public class Car {
    private final String human;
    private final String customer;

    public RealCarShop(String human, String customer) {
        this.human = human;
        this.customer = customer;
    }

    public void sellCar() {
        System.out.println(human + "寻找买家");
        findCar();
        result();
    }

    public void findCar() {
        System.out.println(customer + "寻找卖家");
    }
    public void result() {
        System.out.println(human + "和" + customer + "买卖成功");
    }
}
// 动态代理类(实现方法拦截器接口) //
// MethodInterceptor接口来自net.sf.cglib.proxy.MethodInterceptor或org.springframework.cglib.proxy.MethodInterceptor
public class CglibProxy implements MethodInterceptor {
    public Object createCglibProxy(Class<?> targetClass) {
        Enhancer enhancer = new Enhancer();  // 创建增强器,用来创建动态代理类
        enhancer.setSuperclass(targetClass); // 为增强器指定要代理的业务类,即为生成的代理类指定父类
        enhancer.setCallback(this);          // 设置回调(对于代理类上所有方法的调用,都会调用CallBack)
        return enhancer.create(); // 创建动态代理类对象并返回

        // 以上语句可简化为:return Enhancer.create(targetClass, this); //
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理开始"); // 扩展进行额外的功能操作(如鉴权、计时、日志等)
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("cglib代理结束");   // 扩展进行额外的功能操作(如鉴权、计时、日志等)
        return result;
    }
}

特点

  1. 无法final/static的方法(通过继承被代理的类实现,所以无法动态代理final类)
  2. 可以代理普通类

Spring中使用jdk和cglib相结合的方式进行实现动态代理

实践应用

AOP

面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术

Spring中模块的关键单元是,在AOP中模块的关键单元是切面,以下是与AOP相关的基本概念

  1. 切面(ASPECT):配置类,我们所想要实现的内容。
  2. 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  3. 目标(Target):被通知对象。
  4. 代理(Proxy):向目标对象应用通知之后创建的对象。
  5. 切入点(PointCut):切面通知执行的“地点”的定义。
  6. 连接点(JointPoint):与切入点匹配的执行点。

示例代码

实现方式多样,可参考该文章:Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC

总结

AOP实现原理即采用动态代理的方式,对目标对象进行”强化“,添加相关的前置、后置、环绕或返回异常等场景下的内容,让业务更加灵活,开发更加方便有效

标签:customer,String,代理,模式,human,println,public
来源: https://www.cnblogs.com/cwtjyy/p/15712345.html