《读_Head_First_有感》_“代理模式_完结”

转载自我的朋友tjhuey

前言:
今天是设计模式我想说的最后模式————代理模式代理模式我认为是最重要的模式了,常用于开源框架底层封装,如Spring,Mybatis,HDFS,RPC,xxl-job 等;主要是aop的思想,业务中常用日志切面,接口访问量,并发量控制,简单的说是拦截相关请求做自己想做的事等,今天简单写个例子,并分享一下相关源码

今日主题

代理模式:概述:为其他对象提供一种代理可以控制这个对象的访问

场景:

假设某些操作处理,需要其他事物执行,并在执行时动态的去扩展,可以采用。
在这里,我简单写了个demo,模拟某些操作需要代理,其中计算操作代理,计算操作前后需要处理一些事情。

代码如下

'设计模式'代码

package com.huey.designpattern.dynamicproxy;

/**
* ┏┓   ┏┓
* ┏┛┻━━━┛┻┓
* ┃       ┃  
* ┃   ━   ┃
* ┃ ┳┛ ┗┳ ┃
* ┃       ┃
* ┃   ┻   ┃
* ┃       ┃
* ┗━┓   ┏━┛
* ┃   ┃ 神兽保佑        
* ┃   ┃ 代码无BUG!
* ┃   ┗━━━┓
* ┃       ┣┓
* ┃       ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
 * @author huey
 * @Description : 代理操作
 * @Date Created in 2018/10/21 20:23
*/
public interface ProxyOperation<T> {

    /**
     * @author huey
     * @Description : 其他对象初始化
     * @Date Created in 2018/10/21 20:27
     */
    void init();
    /**
     * @author huey
     * @Description : 钩子 是否计算了
     * @Date Created in 2018/10/21 20:25
     */
    boolean isCalc(boolean flag);

    /**
     * @author huey
     * @Description : 计算后,其他对象后置处理
     * @Date Created in 2018/10/21 20:27
     */
    void postProcessor();
}
package com.huey.designpattern.dynamicproxy;

/**
* ┏┓   ┏┓
* ┏┛┻━━━┛┻┓
* ┃       ┃  
* ┃   ━   ┃
* ┃ ┳┛ ┗┳ ┃
* ┃       ┃
* ┃   ┻   ┃
* ┃       ┃
* ┗━┓   ┏━┛
* ┃   ┃ 神兽保佑        
* ┃   ┃ 代码无BUG!
* ┃   ┗━━━┓
* ┃       ┣┓
* ┃       ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
 * @author huey
 * @Description : 业务:计算
 * 实际目标对象接口
 * @Date Created in 2018/10/21 20:18
*/
public interface ProxyCalcOperation extends ProxyOperation {

     void calc();
}
package com.huey.designpattern.dynamicproxy;

import lombok.extern.slf4j.Slf4j;

/**
 * ┏┓   ┏┓
 * ┏┛┻━━━┛┻┓
 * ┃       ┃
 * ┃   ━   ┃
 * ┃ ┳┛ ┗┳ ┃
 * ┃       ┃
 * ┃   ┻   ┃
 * ┃       ┃
 * ┗━┓   ┏━┛
 * ┃   ┃ 神兽保佑
 * ┃   ┃ 代码无BUG!
 * ┃   ┗━━━┓
 * ┃       ┣┓
 * ┃       ┏┛
 * ┗┓┓┏━┳┓┏┛
 * ┃┫┫ ┃┫┫
 * ┗┻┛ ┗┻┛
 *
 * @author huey
 * @Description : 业务默认计算操作目标对象
 * @Date Created in 2018/10/21 20:21
 */
@Slf4j
public class ProxyCalcOperationDefault implements ProxyCalcOperation {

    @Override
    public void calc() {
        log.info("ProxyCalcOperationDefault --> {}","calc");
    }

    /**
     * @author huey
     * @Description : 其他对象初始化
     * @Date Created in 2018/10/21 20:27
     */
    @Override
    public void init() {
        log.info("ProxyCalcOperationDefault --> {}","init");
    }

    /**
     * @param flag
     * @author huey
     * @Description : 钩子 是否计算了
     * @Date Created in 2018/10/21 20:25
     */
    @Override
    public boolean isCalc(boolean flag) {
        return false;
    }

    /**
     * @author huey
     * @Description : 计算后,其他对象后置处理
     * @Date Created in 2018/10/21 20:27
     */
    @Override
    public void postProcessor() {
        log.info("ProxyCalcOperationDefault --> {}","postProcessor");
    }
}
package com.huey.designpattern.dynamicproxy;

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

/**
 * ┏┓   ┏┓
 * ┏┛┻━━━┛┻┓
 * ┃       ┃
 * ┃   ━   ┃
 * ┃ ┳┛ ┗┳ ┃
 * ┃       ┃
 * ┃   ┻   ┃
 * ┃       ┃
 * ┗━┓   ┏━┛
 * ┃   ┃ 神兽保佑
 * ┃   ┃ 代码无BUG!
 * ┃   ┗━━━┓
 * ┃       ┣┓
 * ┃       ┏┛
 * ┗┓┓┏━┳┓┏┛
 * ┃┫┫ ┃┫┫
 * ┗┻┛ ┗┻┛
 *
 * @author huey
 * @Description : 代理简单工具类
 * @Date Created in 2018/10/21 20:33
 */
public class ProxyOperationUtil {

    public static ProxyCalcOperation getProxy(ProxyOperation proxyOperation) {

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

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

        //代理类执行的代码,lamda,联想aop
        InvocationHandler h = (proxy, method, args) -> {
            //前置扩展,非业务代码,模拟其他方法栈调用
            proxyOperation.init();
            //目标方法
            Object result = method.invoke(proxyOperation, args);

            //后置扩展,非业务代码,模拟其他方法栈调用
            proxyOperation.postProcessor();
            return result;
        };
        ProxyCalcOperation newProxyInstance = (ProxyCalcOperation) Proxy.newProxyInstance(loader, interfaces, h);
        return newProxyInstance;
    }
}
package com.huey.designpattern.dynamicproxy;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

@Slf4j
public class ProxyOperationTest {

    /**
     * @author huey
     * @Description : 普通
     * @Date Created in 2018/10/21 20:52
     */

    @Test
    public void test1() {
        ProxyCalcOperation proxyCalcOperation = new ProxyCalcOperationDefault();
        proxyCalcOperation.calc();
    }

    /**
     * @author huey
     * @Description : 代理
     * @Date Created in 2018/10/21 20:52
     */
    @Test
    public void test2() {
        ProxyCalcOperation proxyCalcOperation = new ProxyCalcOperationDefault();
        // 从源码中得知,设置这个值,可以把生成的代理类,输出出来。
        ProxyCalcOperation proxy = ProxyOperationUtil.getProxy(proxyCalcOperation);
        proxy.calc();
    }

    /**
     * @author huey
     * @Description : 生成后 反编译下 查看
     * @Date Created in 2018/10/21 22:13
     */
    @Test
    public void test3() {
        //生成的jdk代理类
        byte[] bytes = ProxyGenerator.generateProxyClass("$ProxyTl", new Class[]{ProxyCalcOperation.class});
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("E:\\company\\$ProxyTl.class");
            fileOutputStream.write(bytes);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

联想

spring中的代理模式是什么样的呢?简单列出了4个图,jdk和cglib两种方式,默认jdk,UT3中的代理类反编译后可看默认继承Proxy实现目标接口,为啥jdk代理必须是接口形式呢,其实很简单,因为java是单继承。如果哪天再总结spring的小编再跟踪下

spring_jdk_proxy.png

spring_cglib_proxy_1.png

spring_cglib_proxy_2.png

is_cglib_default.png

jdk代理源码配图

1.png

2.png

3.png

4.png

5.png

6.png

7.png

8.png

总结

设计模式【六大原则和23种模式】是个学不完的东西,还是要看自己想到哪种程度,读源码,了解框架,非常的敏感,过瘾
最后,谢谢读者们的欣赏,也希望指出其中的不足,小编还会继续边学习边总结
谢谢HeadFirst 作者。设计模式的学习层面结束了




 

猜你喜欢

转载自blog.csdn.net/weixin_38970751/article/details/83387139