文档章节

代理模式之Java动态代理

凯文加内特
 凯文加内特
发布于 2015/03/09 09:51
字数 886
阅读 34
收藏 0

1. Overview

Java在java.lang.reflect包下,定义了自己的代理。利用这个包下的类,我们可以在运行时动态地创建一个代理类,实现一个或多个接口。并将方法的调用转发到你所指定的类。因为实际代理是在运行时创建的,所以称为:动态代理。

Proxy:完全由java产生的,而且实现了完整的subject接口。

InvocationHandler:Proxy上的任何方法调用都会被传入此类,InvocationHandler控制对RealSubject的访问。

因为Java已经帮助我们创建了Proxy类,我们需要有办法告诉Proxy类你要做什么,我们不能像以前一样把代码写入到Proxy类中,因为Proxy类不是我们实现的。那么我们应该放在哪里?放在InvocationHandler类中,InvocationHandler类是响应代理的任何调用。我们可以吧InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。

2. java.lang.reflect.InvocationHandler

被代理实例所实现的一个接口,内部只有一个invoke()方法,签名如下;

Java代码

public Object invoke(Object proxy, Method method, Object[] args)

当代理的方法被调用的时候,代理就会把这个调用转发给InvocationHandler,也就会调用它的invoke()方法。

3. java.lang.reflect.Proxy

提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类,我们经常使用的静态方式是:

Java代码

newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

4. 示例:

情形:自己可以查看修改姓名性别,但是不能修改rate。他人可以查看姓名,性别以及修改rate,但是不能修改姓名性别。

4.1 定义一个接口:

Java代码

public interface Person {     
         
    String getName();     
         
    String getGender();     
         
    void setName(String name);     
         
    void setGender(String gender);     
         
    void setRate(int rate);     
         
    int getRate();     
}

4.2 定义实现Person接口类

Java代码

public class PersonImpl implements Person {     
String name;     
    
String gender;     
    
String interests;     
    
int rate;     
    
public String getName() {     
    return name;     
}     
    
public void setName(String name) {     
    this.name = name;     
}     
    
public String getGender() {     
    return gender;     
}     
    
public void setGender(String gender) {     
    this.gender = gender;     
}     
    
public String getInterests() {     
    return interests;     
}     
    
public void setInterests(String interests) {     
    this.interests = interests;     
}     
    
public int getRate() {     
    return rate;     
}     
    
public void setRate(int rate) {     
    this.rate = rate;     
}

4.3 定义OwnerInvocationHandler类,表示如果为本人,则可以进行修改查看姓名性别。

Java代码

public class OwnerInvocationHandler implements InvocationHandler{     
         
    private Person personBean;     
         
    public OwnerInvocationHandler(Person personBean){     
        this.personBean = personBean;     
    }     
         
    @Override    
    public Object invoke(Object proxy, Method method, Object[] args)     
            throws IllegalAccessException {     
             
        try {     
            if(method.getName().startsWith("get")){//如果方法名为get,就调用person类内的get相应方法     
    
                return method.invoke(personBean, args);     
            }else if(method.getName().equals("setRate")){ // 如果方法是setRate,则抛出异常     
                throw new IllegalAccessException("access deny");     
            }else if(method.getName().startsWith("set")){  //如果为set,就调用person类内的set相应方法     
                return method.invoke(personBean, args);     
            }else {     
                System.out.println("non method invoke");     
            }     
        } catch (InvocationTargetException e) {     
            e.printStackTrace();     
        }     
        return null;      
             
    }     
         
}

4.4 定义NonInvocationHandler类,表示如果不为本人,则可以进行查看姓名性别和修改rate。

Java代码

public class NonInvocationHandler implements InvocationHandler{     
    //     
    private Person person;     
         
    public NonInvocationHandler(Person person){     
        this.person = person;     
    }     
    
    @Override    
    public Object invoke(Object proxy, Method method, Object[] args)     
            throws Throwable {     
        if(method.getName().startsWith("setRate")){     
            return method.invoke(person, args);     
        }else if (method.getName().startsWith("get")){     
            return method.invoke(person, args);     
        } else {     
            System.out.println("non method invoke");     
            return null;     
        }     
    }     
         
}

4.5 测试类MyDynamicProxy

Java代码

public class MyDynamicProxy {     
    
public Person getOwnerPersonBeanProxy(Person person){     
    return (Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),      
            person.getClass().getInterfaces(), new OwnerInvocationHandler(person));     
}     
    
public Person getNonPersonBeanProxy(Person person){     
    return (Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),      
            person.getClass().getInterfaces(), new NonInvocationHandler(person));     
}     
    
public static void main(String[] args) {     
    MyDynamicProxy mdp = new MyDynamicProxy();     
    mdp.test();     
         
}     
    
public void test(){     
                //     
    Person person = getPersonBeanFromDB1();     
    Person personProxy = getOwnerPersonBeanProxy(person);     
    System.out.println(personProxy.getName());      
    try {     
        personProxy.setRate(2);     
    } catch (Exception e) {     
        System.out.println("can not setRate");     
    }     
                 //     
    Person person1 = getPersonBeanFromDB1();     
    Person personProxy2 = getNonPersonBeanProxy(person1);     
    System.out.println(personProxy2.getName());     
    personProxy2.setRate(2);     
    System.out.println(personProxy2.getRate());     
}     
    
private Person getPersonBeanFromDB1(){     
    Person pb = new PersonImpl();     
    pb.setName("remy");     
    pb.setGender("girl");     
    pb.setRate(1);     
    return pb;     
}

输出结果:

Java代码

remy     
can not setRate     
remy     
2


本文转载自:http://developer.51cto.com/art/201104/253625.htm

凯文加内特
粉丝 341
博文 701
码字总数 110786
作品 0
青岛
后端工程师
私信 提问
设计模式3——Proxy设计模式

Proxy代理设计模式是一种控制对象访问的设计模式,类似于网络代理,网络代理机制如下图: Proxy代理设计模式机制如下: 代理模式UML图如下: 代理模式顺序图如下: 客户端程序通过代理程序来...

小米米儿小
2013/12/06
274
0
100行代码让您学会JavaScript原生的Proxy设计模式

面向对象设计里的设计模式之Proxy(代理)模式,相信很多朋友已经很熟悉了。比如我之前写过代理模式在Java中实现的两篇文章: Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理 ...

全部原谅
2018/08/28
8
0
Java之23种设计模式解析(二)

B、结构模式(7 种) 我们接着讨论设计模式,上篇文章我讲完了 5 种创建型模式,这章开始,我将讲下 7 种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模...

wersdffg
2015/02/15
151
0
面试官:Spring中用了哪些设计模式?

前言 设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪...

Java填坑路
02/15
563
0
设计模式知识汇总(附github分享)

写在前面 主要内容 为了更系统的学习设计模式,特地开了这样一个基于Java的设计模式【集中营】,都是笔者在实际工作中用到过或者学习过的一些设计模式的一些提炼或者总检。慢慢地初见规模,也...

landy8530
2018/10/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【1015】LNMP架构二

【1015】LNMP架构二 三、PHP安装 PHP安装和LAMP安装PHP方法有差别,需要开启php-fpm服务 1、下载PHP7至/usr/local/src/ 切换目录:cd /usr/local/src 2、解压缩 tar -jxvf php-7.3.0.tar.gz...

飞翔的竹蜻蜓
33分钟前
4
0
浅谈Visitor访问者模式

一、前言 什么叫访问,如果大家学过数据结构,对于这点就很清晰了,遍历就是访问的一般形式,单独读取一个元素进行相应的处理也叫作访问,读取到想要查看的内容+对其进行处理就叫作访问,那么...

青衣霓裳
52分钟前
6
0
JS内嵌多个页面,页面之间如何更快捷的查找相关联的页面

假设parent为P页面, P页面有两个子页面,分别为B页面和C页面; B页面和C页面分别内嵌一个iframe,分别为:D页面和E页面 现在通过B页面的内嵌页面D的方法refreshEpage(eUrl)来加载内嵌页面E的内容...

文文1
53分钟前
7
0
Hibernate 5 升级后 getProperties 错误

升级到 Hibernate 5 后,提示有错误: org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava/util/Map; 完整的错误栈为: java.lang.NoSuchMethodError: org.hibernate......

honeymoose
54分钟前
6
0
mysql-connector-java升级到8.0后保存时间到数据库出现了时差

在一个新项目中用到了新版的mysql jdbc 驱动 <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId>     <version>8.0.18</version> ......

ValSong
58分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部