10设计模式-结构型模式-代理模式

导读:本篇文章讲解 10设计模式-结构型模式-代理模式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

代理模式概述

代理模式(Proxy Pattern) ,给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。
讲人话:在系统内原来代码不懂得情况下,就是现在想找个人帮忙干活,并且在干活的前后还需要处理一些别的业务逻辑,完成对应的目标

1、静态代理

在这里插入图片描述

代码

// 被代理父类【今后得代码一定要思考是否要使用父类】

package com.xusj.future.structural.proxy.statics;

/**
 * @author xusj
 * <br>CreateDate 2022/7/28 22:57
 */
public interface ManTikTok {
    void tikTok();
}

// 被代理

package com.xusj.future.structural.proxy.statics;

/**
 * @author xusj
 * <br>CreateDate 2022/7/28 22:58
 */
public class ZhangTikTok implements ManTikTok {
    @Override
    public void tikTok() {
        System.out.println("我实现了接口");
    }
}

// 代理类【聚合被代理类,使用多态,聚合顶层父类,代码扩展性增加】

package com.xusj.future.structural.proxy.statics;

/**
 * @author xusj
 * <br>CreateDate 2022/7/28 22:59
 */
public class MyProxy implements ManTikTok {
    // 被代理对象(多态)
    private ManTikTok manTikTok;

    // 构造方法(多态)
    public MyProxy(ManTikTok manTikTok) {
        this.manTikTok = manTikTok;
    }


    @Override
    public void tikTok() {
        // 代理之前,我能干事情
        System.out.println("我是代理宝强干活的宋喆");
        // 代理之后我还能干一些事情
    }
}

静态代理:需要现实同一个接口
(1)优点:在不修改目标对象的功能前提下, 能通过代理对象对目标对象进行功能扩展
(2)缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类;
一旦接口增加方法,目标对象与代理对象都要维护【维护成本高】

动态代理

// 被代理顶层接口1

public  interface ManTikTok {
   void tiktok();
}

// 被代理顶层接口2

public interface SellTikTok {

    void sell();
}

// 被代理实现类

public class LeiTikTok  implements ManTikTok,SellTikTok {
    @Override
    public void tiktok() {
        System.out.println("tiktok.... ");
    }

    @Override
    public void sell() {
        System.out.println("只要666,赶紧来包...");
    }

    public void haha(){
        System.out.println("hahaha ,......");
    }
}

// 代理类

public class JdkTiktokProxy<T> implements InvocationHandler {


    private T target;
    //接受被代理对象
    JdkTiktokProxy(T target){
        this.target = target;
    }
    /**
     * 获取被代理对象的  代理对象
     * @param t
     * @param <T>
     * @return
     */
    public static<T> T getProxy(T t) {

        /**
         * ClassLoader loader, 当前被代理对象的类加载器
         * Class<?>[] interfaces, 当前被代理对象所实现的所有接口
         * InvocationHandler h,
         *  当前被代理对象执行目标方法的时候我们使用h可以定义拦截增强方法
         */
        Object o = Proxy.newProxyInstance(
                t.getClass().getClassLoader(),
                t.getClass().getInterfaces(), //必须接口
                new JdkTiktokProxy(t));
        return (T)o;
    }


    /**
     * 定义目标方法的拦截逻辑;每个方法都会进来的
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {

        //反射执行
        System.out.println("真正执行被代理对象的方法");
        Object invoke = method.invoke(target, args);
        System.out.println("返回值:一堆美女");
        return invoke;
    }
}

Cglib动态代理

1)静态代理和JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是 Cglib 代理【通过子类代理】
2)Cglib 代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书
也将Cglib代理归属到动态代理。
3)Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口.它广泛
的被许多 AOP 的框架使用,例如 Spring AOP实现方法拦截就用到了Cglib包
4)在 AOP 编程中如何选择代理模式:【jdk代理和Cglib代理的选择】
目标对象需要实现接口,用 JDK 代理
目标对象不需要实现接口,用 Cglib 代理
5)Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类

// 引入spring核心依赖,整合了cglib得功能

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.18</version>
        </dependency>

// 需要代理得对象(cglib适用只有一个对象)

package com.xusj.future.structural.proxy.cglib;

/**
 * @author xusj
 * <br>CreateDate 2022/7/28 23:41
 */
public class LeiTikTok {
    public void tiktokHaha() {
        System.out.println("雷丰阳,tiktok.... haha....");
    }
}

// cglib动态代理

package com.xusj.future.structural.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author xusj
 * <br>CreateDate 2022/7/28 23:42
 */
public class CglibProxy {
    // 为任意对象创建代理
    public static <T> T createProxy(T t) {
        // 1、创建增强器
        Enhancer enhancer = new Enhancer();
        // 2、设置要增强哪个功能。增强器为这个类动态创建一个子类
        enhancer.setSuperclass(t.getClass());
        // 3、设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj,
                                    Method method,  //为了能获取到原方法的一些元数据信息
                                    Object[] args,
                                    MethodProxy proxy) throws Throwable {
                //编写拦截的逻辑
                System.out.println("cglib上场le .......xxx");
                //当前方法的信息
//                method.get
//                method.getAnnotation()
                //目标方法进行执行
                Object invoke = proxy.invokeSuper(obj, args);
                return invoke;
            }
        });
        Object o = enhancer.create();
        return (T) o;
    }
}

// 测试类

package com.xusj.future.structural.proxy.cglib;

/**
 * @author xusj
 * <br>CreateDate 2022/7/28 23:51
 */
public class Test {
    public static void main(String[] args) {
        //原来的对象都不用new
        LeiTikTok tikTok = new LeiTikTok();

        LeiTikTok proxy = CglibProxy.createProxy(tikTok);

        proxy.tiktokHaha();
    }

}

语雀详细地址

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/96217.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!