设计模式_代理_动态代理

1.代理模式概述

1.1什么是代理模式

ProxyPattern(即:代理模式)23种常用的面向对象软件的设计模式之一。
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
作用:增强一个类中的某个方法.对程序进行扩展. Spring框架中AOP.

1.2动态代理介绍

动态代理它可以直接给某一个目标(被代理 对象)对象(实现了某个或者某些接口)生成一个代理对象,而不需要代理类存在。
动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。

动态代理的分类

  • jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
  • spring中动态代理:cglib

2.jdk中的动态代理的使用

2.1API介绍

Java.lang.reflect.Proxy类可以直接生成一个代理对象

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
参数1:ClassLoader loader 代理对象的类加载器 一般使用被代理对象的类加载器
参数2:Class<?>[] interfaces 代理对象的要实现的接口 一般使用的被代理对象实现的接口
参数3:InvocationHandler h (接口)执行处理类

InvocationHandler中的invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行
-参数3.1Object proxy:代理对象(慎用)
-参数3.2Method method:当前执行的方法
-参数3.3Object[] args:当前执行的方法运行时传递过来的参数
返回值:当前方法执行的返回值

2.2代码实现

/**  规范接口
 * Created by liangtong.
 */
public interface Actor {
    /**
     * 唱歌
     * @return
     */
    public String sing();

    /**
     * 跳舞
     * @return
     */
    public String dance();
}
/** 目标类:刘德华类,需要被代理的类。
 * Created by liangtong.
 */
public class Liudehua implements Actor {
    @Override
    public String sing() {
        return "华仔唱歌";
    }

    @Override
    public String dance() {
        return "华仔跳舞";
    }
}
public class TestProxy {
    /*
    1.工具类 Proxy.newProxyInstance(); 运行时创建代理类
        Object object = Proxy.newProxyInstance()
    2. 参数
        参数1:类加载器,负责将新创建的类添加到内存中。
        参数2:确定需要实现接口们,java可以多实现,需要同一个数组。
        参数3:处理类,接口InvocationHandler
            //调用代理类的每一个方法,都将执行处理类的invoke方法。
            参数a) proxy 代理类,一般没用
            参数b) method 当前执行的方法
            参数c) args 方法的实际参数
 */
    @Test
    public void testDemo2(){
        //目标类
        Actor target = new Liudehua();
        //1 类加载  代理对象的类加载器  责将新创建的类添加到内存中
        ClassLoader classLoader = TestProxy.class.getClassLoader();
        //2 接口   代理对象的要实现的接口
        Class[] interfaces = {Actor.class};
        //3 处理类,接口InvocationHandler
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理收钱之后!");
                return method.invoke(target,args);
            }
        };
        //创建目标类
        Actor actor = (Actor) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        //调用方法并打印
        System.out.println(actor.sing());
        System.out.println(actor.dance());
    }
}

2.4代码实现(加强)

public interface Person {

    void eat();

    void sleep(Integer hours);
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Wash {

}
public class Student implements Person {
    @Override
    public void eat() {
        System.out.println("学生在吃饭");
    }

    @Wash
    @Override
    public void sleep(Integer hours) {
        System.out.println("学生在睡觉,睡了" + hours + "个小时");
    }
}
public class PersonFactory {

    public static Person getPerson() {
        //增强
        Student student = new Student();
        ClassLoader classLoader = student.getClass().getClassLoader();
        Class<?>[] interfaces = student.getClass().getInterfaces();

        Person obj = (Person) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {

            /**
             *
             * @param proxy 代理对象
             * @param method 代理方法
             * @param args 调用代理方法时传递的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                Class<?>[] argClass = null;
                if (args != null) {
                    argClass = new Class[args.length];
                    //获取所有参数的类型
                    for (int i = 0; i < args.length; i++) {
                        argClass[i] = args[i].getClass();
                    }
                }

                //获取方法名
                String methodName = method.getName();

                //获取原始的方法
                Method originMethod = student.getClass().getMethod(methodName, argClass);
                System.out.println(originMethod);

                //判断方法是否需要增强
                if (originMethod.isAnnotationPresent(Wash.class)) {
                    System.out.println("之前洗漱");

                    Object obj = method.invoke(student, args);

                    System.out.println("之后洗漱");
                    return obj;
                }

                return method.invoke(student, args);
            }
        });
        return obj;
    }
}
public class StudentTest {
    @Test
    public void test() {
        Person person = PersonFactory.getPerson();
        person.eat();
        person.sleep(8);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容