首页 > 编程语言 >java代理模式及动态代理类

java代理模式及动态代理类

时间:2023-05-11 14:31:49浏览次数:37  
标签:java 对象 Object request 代理 动态 public Subject

1.      代理模式

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式一般涉及到的角色有:

抽象角色:声明真实对象和代理对象的共同接口;

代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。(参见文献1)

以下以《Java与模式》中的示例为例:

抽象角色:

abstract public class Subject
{
   
abstract public void request();
}
真实角色:实现了Subject的request()方法。
public class RealSubject extends Subject

{
      
public RealSubject()
      
{ 
      
}
      

      
public void request()
      
{ 
      
       System.out.println("From real subject.");
      
}
}

代理角色:

public class ProxySubject extends Subject

{
   
private RealSubject realSubject;  //以真实角色作为代理角色的属性
      

      
public ProxySubject()
      
{
      
}
 
      
public void request()  //该方法封装了真实对象的request方法
      
{
       
preRequest();  
      
       if( realSubject == null )
       
{
             
       realSubject = new RealSubject();
             
}
       
realSubject.request();  //此处执行真实对象的request方法
       
postRequest(); 
      
}
 
   
private void preRequest()
   
{
       
//something you want to do before requesting
   
}
 
   
private void postRequest()
   
{
       
//something you want to do after requesting
   
}
}

客户端调用:

Subject sub=new ProxySubject();

Sub.request();

       由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他方法(preRequest(),postRequest()),可以处理一些其他问题。

       另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

 

2.动态代理类

       Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:

(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:

Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。

Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

       所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。(参见文献3)

    在使用动态代理类时,我们必须实现InvocationHandler接口,以第一节中的示例为例:

抽象角色(之前是抽象类,此处应改为接口):

public interface Subject
{
   
abstract public void request();
}

具体角色RealSubject:同上;

 

代理角色:

import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
 
public class DynamicSubject implements InvocationHandler {
 
private Object sub;
 
 
public DynamicSubject() {
 
}
 
 
public DynamicSubject(Object obj) {
   
sub = obj;
 
}
 
 
 
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
System.out.println("before calling " + method);
 
   
method.invoke(sub,args);
 
   
System.out.println("after calling " + method);
   
return null;
 
}
 
}

       该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;此外,在该类还实现了invoke方法,该方法中的

method.invoke(sub,args);

其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或之后执行一些相关操作。

客户端

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
 
public class Client
{
 
   
static public void main(String[] args) throws Throwable
      
{
     
RealSubject rs = new RealSubject();  //在这里指定被代理类
     
InvocationHandler ds = new DynamicSubject(rs);  //初始化代理类
      
  Class cls = rs.getClass();
     
//以下是分解步骤
     
/*
    
 Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;
    
 Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});
    
 Subject subject =(Subject) ct.newInstance(new Object[]{ds});
    
*/
    
//以下是一次性生成
     
Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),
                                
cls.getInterfaces(),ds );

      subject.request();
}

       通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系(参见文献2)。

 

 

参考文献:

1.      阎宏,《Java 与模式》

2.          透明,《动态代理的前世今生》

3.   Forest Hou,《Dynamic Proxy 在 Java RMI 中的应用》



标签:java,对象,Object,request,代理,动态,public,Subject
From: https://blog.51cto.com/u_16107052/6266585

相关文章

  • JavaWeb之Servlet本质
    Servlet:服务器和Wepapp开发者之间的协议,sun公司已经规范了Servlet协议,Wepapp开发者只需要去实现规范接口类和对应的配置文件即可,Servlet底层是面向接口编程,用反射机制实例化一个类后再向下转型成Servlet类(因为Wepapp开发者实现规范好,只需到对应的文件中调用各个方法)菜鸟教程的解......
  • Java 9模块化关键字及应用场景
    一、背景SpringBoot3.0最低要求jdk17,为跟上节奏储备知识。二、简介关键字描述应用场景module定义一个模块代码隔离,依赖控制,代码可重用性openmodule定义一个像java9之前的开放模块像Java的旧版本那样允许完全反射exports...to指定模块的一部分对外提供......
  • Java 服务 CPU 占用过高排查
    先需要找出那个进程占用CPU高。top列出系统各个进程的资源占用情况。然后根据找到对应进行里哪个线程占用CPU高。top-Hp进程ID列出对应进程里面的线程占用资源情况找到对应线程ID后,再打印出对应线程的堆栈信息printf"%x\n"PID把线程ID转换为16进制。......
  • Linux重启Java的.sh脚本shell
    原文链接:https://blog.csdn.net/weixin_44821965/article/details/130039771前言最近看到了项目中重启Java服务的.sh文件,对sh文件里面的命令产生了好奇,于是研究了一下脚本里面每一个命令的具体意义一、.sh文件内容.sh文件里面的内容如下:ps-ef|grepplugins-web|grep-vgre......
  • 动态避障,机器人动态障碍物避障程序,有四个障碍物,障碍物是移动的,程序为机器人动态障碍物
    动态避障,机器人动态障碍物避障程序,有四个障碍物,障碍物是移动的,程序为机器人动态障碍物避障程序,可以显示障碍物的运动轨迹以及机器人的运动轨迹ID:3969667311724516......
  • Java---内部类
    Java---内部类内部类的概念内部类就是一个类内部包含另一个类分类:成员内部类局部内部类(包含匿名内部类)格式:修饰符class外部类名称{修饰符class内部类名称{//}}注意:内用外,随意访问;外用内,需要内部类对象.代码示例publicclassBody{privateSt......
  • Java8相对于Java7新增了什么新特性
    Java8和Java7是两个不同的Java版本,Java8相对于Java7引入了相当多的新特性,以下是Java8相对于Java7新增的重要特性:Lambda表达式:Lambda表达式是Java8最重要的特性之一,它提供了一种简洁的编写匿名函数的方式,有助于编写更加易读和简单的代码。函数式接口和......
  • 【Java】Stream的一些日常操作
    1  前言 Java8出来的stream写法让我们对数据的处理带来了一些写法上的增进,这节就简单记录下平时使用的stream的一些操作,关于stream的书籍,可以看一下Java8实战,里边会有两三章讲解我们的stream。2 常用记录 //根据单个属性或者多个属性去重List<Object>data......
  • java线程池和多线程的使用详解
    Java多线程和线程池使用java多线程实现的几种方法1.继承Thread类继承Thread类,重写run方法,创建线程类对象调用start方法启动线程。publicclassThreadDemo{/***继承Thread类创建线程*/publicstaticclassMyThreadextendsThread{publ......
  • 为什么推荐大家用动态ip?
    随着时代发展,现在黑客技术已经越来越厉害,很多企业都开始更换动态IP,如果你还在使用静态IP,从目前黑客技术来看,就会非常危险。也许单纯这样说,可能大家无法理解为何企业要使用动态IP,现在就来看看使用动态IP都有什么好处。1.不易被黑客锁定黑客想要doss一个网站,首先就要找到网站IP,......