代理模式啦

代理模式

一.介绍

是一种常见的设计模式,属于结构型模式.

它的核心思想是通过一个 代理对象 来控制对真实对象的访问

从而在不修改目标对象的前提下,实现功能的增强

1.使用场景

  • 权限控制

  • 日志记录

  • 性能检测

  • 缓存的处理

2.分类

  • 静态代理

    • 在编译阶段

    • 在写代码期间

    • 在程序运行之前,就已经确定了代理类和被代理的类的关系

  • 动态代理

    • 在写代码期间,不确定被代理的类是谁

    • 只知道写代理类和他的业务逻辑

    • 在运行的时候,动态的创建代理类,灵活性比较高

二.静态代理

在编码阶段,已经明确知道哪个类是真实类,哪个类是代理类,二者的关系是硬编码的.

1.案例:程序员接项目

1.1 定义接口:Programmer
//程序员
public interface Programmer {
​
    void code(Integer money);
}
1.2 真实类
public class XiaoMing implements Programmer{
    @Override
    public void code(Integer money) {
        if (money < 7000){
            System.out.println("拒绝上班");
            return;
        }
        System.out.println("获得工资:"+money);
        System.out.println("开开心心写代码");
    }
}
1.3 代理类: OD公司作为代理类,承接业务
//代理类,对外说自己是程序员,其实不会写代码,需要一个真实的程序员来给他写代码
public class OD implements Programmer{
​
    private final Programmer programmer;
​
    public OD(Programmer programmer){
        this.programmer = programmer;
    }
​
    @Override
    public void code(Integer money) {
        System.out.println("收到甲方的工资:"+money);
        Integer payMoney = 10000;
        //保险
        Double xian = payMoney * 0.12;
        Double jin = payMoney * 0.12;
        //公司付出
        System.out.printf("公司付出:缴纳五险一金,保险%s元,公积金%s元\n",xian,jin);
        System.out.printf("实际发的工资:%s\n",payMoney);
        programmer.code(payMoney);
        System.out.println("公司赚了:"+(money - xian - jin - payMoney));
    }
}
1.4 测试类
public class Hua {
    public static void main(String[] args) {
        //需要一个野生的程序员,小明
        Programmer xiaoming = new XiaoMing();
        //招聘小明,开发
        Programmer od = new OD(xiaoming);
        //支付工资
        od.code(40000);
    }
}
1.5 特点
  • 优点

    • 逻辑清晰

    • 易于理解和实现

  • 缺点

    • 每个真实类,都需要一个对应的代理类

    • 非常不利于维护和扩展

    • 不适合大规模的使用

三.动态代理

动态代理是在程序运行期间动态的生成代理类,具有更高的灵活性和通用性

常见的实现方式有两种:

类型实现机制依赖环境
JDK动态代理基于接口实现必须有接口
CGLib动态代理基于继承实现可以没有接口,需要引入cglib库

1.JDK动态代理

  • 案例:方法执行的时候,统计运行时机,和性能

1.1 自定义: InvocationHandler
public class JDKInvocationHandler implements InvocationHandler {
    //真实类
    private Object target;
​
    public JDKInvocationHandler(Object object){
        this.target = object;
    }
​
    //Method 是被执行方法的 方法对象
    //args 被执行方法的参数
    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {
        //这个方法是用来写业务的---统计性能
        //进入方法的时候,记录时间
        long start = System.currentTimeMillis();
        // result 是方法执行之后的返回值
        Object result = method.invoke(target,args);
        //执行之后的时间
        long time = System.currentTimeMillis() - start;
        System.out.printf("[性能统计]方法%s,耗时%s ms \n",method.getName(),time);
        return result;
    }
}

这里只写了业务逻辑,此时,还不知道被统计性能的类是谁

刚刚的代理类,会在运行时,动态生成

1.2 使用示例
public class TestJdk {
    public static void main(String[] args) {
        f2();
    }
​
    private static void f2() {
        //真实类
        WebUserServiceImpl webUserServiceImpl = new WebUserServiceImpl();
        JDKInvocationHandler jdkInvocationHandler =
                new JDKInvocationHandler(webUserServiceImpl);
        WebUserService webUserService =
                (WebUserService) Proxy.newProxyInstance(
                        WebUserServiceImpl.class.getClassLoader(),
                        new Class[]{WebUserService.class},
                        jdkInvocationHandler
                );
        webUserService.findById(100);
    }
​
    private static void f1() {
        XiaoMing xiaoMing = new XiaoMing();
        //jdk 动态代理对象
        JDKInvocationHandler jdkInvocationHandler =
                new JDKInvocationHandler(xiaoMing);
        //创建Programer 代理对象
        //创建的代理对象,具备jdkInvocationHandler中的能力
        Programmer programmer = (Programmer) Proxy.newProxyInstance(
                XiaoMing.class.getClassLoader(),//真实类
                new Class[]{Programmer.class},//接口
                jdkInvocationHandler//动态代理对象
        );
        programmer.code(30000);
    }
}

2 Cglib动态代理

因为Spring中已经包含了Cglib库,所以不再重新引入

  • 案例: 日志打印

2.1 自定义Cglib代理工厂
public class CglibProxyFactory implements MethodInterceptor {
​
    //真实类
    private Object target;
​
    public Object getInstance(Object target){
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
​
    @Override
    public Object intercept(Object proxy,
                            Method method,
                            Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        System.out.println("[cglib]"+method.getName()+"方法被执行,参数:"+ Arrays.toString(args));
        //执行方法
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("cglib,返回值:"+result);
        return result;
    }
}
2.2 测试
public class CglibTest {
    public static void main(String[] args) {
        //真实类
        WebUserServiceImpl webUserServiceImpl = new WebUserServiceImpl();
        //工厂类
        CglibProxyFactory factory = new CglibProxyFactory();
        //设置真实类
        WebUserService webUserService = (WebUserService) factory.getInstance(webUserServiceImpl);
        WebUser webUser = webUserService.findById(99);
    }
}

四.总结

  • 代理模式,代码可以看懂就合格了

  • 重点是能把代理模式描述清楚

  • 有能力了,可以把代码敲一遍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值