【Java笔记】Java——远程监控、反射、代理、内省机制

  1. 远程控制的基本原理
  2. 远程控制(RemoteControl)拥有控制端和被控端双方。 控制方通过请求,取得对远端的操作,实现远端的事件回放功能,同时,应该看得到远端桌面的画面。而被控方必须在建立ServerSocket之后进行对外来请求的鉴听。
  3.  1 /**
     2      * 客户端发送事件
     3      * @param e
     4      */
     5     public void sendEvent(InputEvent e){
     6         try {
     7             SinglClient.getInstance().getOos().writeObject(e);
     8             SinglClient.getInstance().getOos().flush();
     9         } catch (IOException e1) {
    10             e1.printStackTrace();
    11         }
    12     }
  4.  1 /**
     2      * 客户端图片接收
     3      * @throws Exception
     4      */
     5     public void readImage() throws Exception{
     6         int length = SinglClient.getInstance().getOis().readInt();
     7         byte[] bytes = new byte[length];
     8         SinglClient.getInstance().getOis().readFully(bytes);
     9         //转换为图片
    10         ImageIcon image = new ImageIcon(bytes);
    11         label.setIcon(image);
    12         label.repaint();
    13     }
  5.   1 package com.edp.client;
      2
      3 import java.awt.Dimension;
      4 import java.awt.Toolkit;
      5 import java.awt.event.InputEvent;
      6 import java.awt.event.KeyAdapter;
      7 import java.awt.event.KeyEvent;
      8 import java.awt.event.MouseAdapter;
      9 import java.awt.event.MouseEvent;
     10 import java.io.IOException;
     11
     12 import javax.swing.ImageIcon;
     13 import javax.swing.JFrame;
     14 import javax.swing.JLabel;
     15
     16
     17 /**
     18  * 监控端的屏幕展示界面
     19  * @author minGe_000
     20  *
     21  */
     22 public class ControlFrame extends JFrame{
     23     private JLabel label;
     24     public void initFrame() {
     25         //建立和服务器的连接
     26         SinglClient.getInstance().getConenction();
     27         //得到屏幕大小
     28         Dimension dimen = Toolkit.getDefaultToolkit().getScreenSize();
     29         this.setSize(dimen);
     30         this.setResizable(false);
     31         this.setDefaultCloseOperation(3);
     32         this.setLocationRelativeTo(null);
     33         this.setUndecorated(true);
     34         label = new JLabel();
     35         this.add(label);
     36         this.setVisible(true);
     37         new Thread(){
     38             public void run() {
     39                 try{
     40                     while(true){
     41                         readImage();
     42                         Thread.sleep(100);
     43                     }
     44                 }catch(Exception e){
     45                     e.printStackTrace();
     46                 }
     47             };
     48         }.start();
     49         //给窗体添加相应的监听
     50         MouseAdapter adapter = new MouseAdapter() {
     51             public void mouseMoved(MouseEvent e) {
     52                 super.mouseMoved(e);
     53                 //发送对象
     54                 sendEvent(e);
     55             }
     56             @Override
     57             public void mouseClicked(MouseEvent e) {
     58                 super.mouseClicked(e);
     59                 //发送对象
     60                 sendEvent(e);
     61             }
     62             @Override
     63             public void mouseReleased(MouseEvent e) {
     64                 super.mouseReleased(e);
     65                 //发送对象
     66                 sendEvent(e);
     67             }
     68             @Override
     69             public void mousePressed(MouseEvent e) {
     70                 super.mousePressed(e);
     71                 //发送对象
     72                 sendEvent(e);
     73             }
     74             @Override
     75             public void mouseDragged(MouseEvent e) {
     76                 super.mouseDragged(e);
     77                 //发送对象
     78                 sendEvent(e);
     79             }
     80         };
     81         this.addMouseListener(adapter);
     82         this.addMouseMotionListener(adapter);
     83         this.addMouseWheelListener(adapter);
     84         //给窗体添加键盘监听
     85         KeyAdapter key = new KeyAdapter() {
     86             @Override
     87             public void keyPressed(KeyEvent e) {
     88                 super.keyPressed(e);
     89                 //发送对象
     90                 sendEvent(e);
     91             }
     92             @Override
     93             public void keyReleased(KeyEvent e) {
     94                 super.keyReleased(e);
     95                 //发送对象
     96                 sendEvent(e);
     97             }
     98         };
     99         this.addKeyListener(key);
    100     }
    101     /**
    102      * 客户端发送事件
    103      * @param e
    104      */
    105     public void sendEvent(InputEvent e){
    106         try {
    107             SinglClient.getInstance().getOos().writeObject(e);
    108             SinglClient.getInstance().getOos().flush();
    109         } catch (IOException e1) {
    110             e1.printStackTrace();
    111         }
    112     }
    113     /**
    114      * 客户端图片接收
    115      * @throws Exception
    116      */
    117     public void readImage() throws Exception{
    118         int length = SinglClient.getInstance().getOis().readInt();
    119         byte[] bytes = new byte[length];
    120         SinglClient.getInstance().getOis().readFully(bytes);
    121         //转换为图片
    122         ImageIcon image = new ImageIcon(bytes);
    123         label.setIcon(image);
    124         label.repaint();
    125     }
    126 }
  6. 反射机制
  7. Person类——用于定义Person对象的属性和方法

    Car类——用于定义Car对象的属性和方法

    Class类——用于定义类对象的属性方法

  8. 得到Class三种方法:
    1. 第一种方式:Object类中的getClass方法

      第二种方式:类.class

      第三种方式:通过Class类的forName方法获取

  9. public Constructor<T> getConstructor(Class<?>... parameterTypes)

    得到制定的公有(public)的类

    public Constructor<?>[] getConstructors()

    得到所有的公有(public)的类

    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

    得到所有的一个指定类

    public Constructor<?>[] getDeclaredConstructors()  得到所有的类

  10.  1 package Reflect;
     2
     3
     4
     5 /**
     6
     7  * 通过一个对象获得完整的包名和类名
     8
     9  * */
    10
    11 class Demo{
    15 }
    16
    17
    18
    19 class hello{
    20
    21     public static void main(String[] args) {
    22
    23         Demo demo=new Demo();
    24
    25         System.out.println(demo.getClass().getName());
    26
    27     }
    28
    29 }

    运行结果:Reflect.Demo

  11.  1 package Reflect;
     2
     3
     4
     5 class Person{
     6
     7
     8
     9     public String getName() {
    10
    11         return name;
    12
    13     }
    14
    15     public void setName(String name) {
    16
    17         this.name = name;
    18
    19     }
    20
    21     public int getAge() {
    22
    23         return age;
    24
    25     }
    26
    27     public void setAge(int age) {
    28
    29         this.age = age;
    30
    31     }
    32
    33     @Override
    34
    35     public String toString(){
    36
    37         return "["+this.name+"  "+this.age+"]";
    38
    39     }
    40
    41     private String name;
    42
    43     private int age;
    44
    45 }
    46
    47
    48
    49 class hello{
    50
    51     public static void main(String[] args) {
    52
    53         Class<?> demo=null;
    54
    55         try{
    56
    57             demo=Class.forName("Reflect.Person");
    58
    59         }catch (Exception e) {
    60
    61             e.printStackTrace();
    62
    63         }
    64
    65         Person per=null;
    66
    67         try {
    68
    69             per=(Person)demo.newInstance();
    70
    71         } catch (InstantiationException e) {
    72
    73             // TODO Auto-generated catch block
    74
    75             e.printStackTrace();
    76
    77         } catch (IllegalAccessException e) {
    78
    79             // TODO Auto-generated catch block
    80
    81             e.printStackTrace();
    82
    83         }
    84
    85         per.setName("Rollen");
    86
    87         per.setAge(20);
    88
    89         System.out.println(per);
    90
    91     }
    92
    93 }

    运行结果:

    Rollen  20

  12. 获得普通方法:
  13. public Method getMethod(String name,Class<?>... parameterTypes)

    public Method[] getMethods()

    public Method getDeclaredMethod(String name,Class<?>... parameterTypes)

    public Method[] getDeclaredMethods()

  14. 获取属性的方法:
  15. public Field getField(String name)

    public Field[] getFields()

    public Field getDeclaredField(String name)

    public Field[] getDeclaredFields()

  16. 获取类信息其他方法
  17. public int getModifiers()

    public Annotation[] getAnnotations()

    public ClassLoader getClassLoader()

    public Class<?>[] getInterfaces()

    public String getName()

    public boolean isAnnotation()

    public boolean isEnum()

    public boolean isInterface()

  18. 代理(Proxy):为其他对象提供一种代理以控制对这个对象的访问
  19. 我们书写执行一个功能的函数时,经常需要在其中写入与功能不是直接相关但很有必要的代 码,如日志记录,信息发送,安全和事务支持等,这些枝节性代码虽然是必要的,但它会带 来以下麻烦:
    1. 枝节性代码游离在功能性代码之外,它下是函数的目的,这是对OO是一种破坏
    2. 枝节性代码会造成功能性代码对其它类的依赖,加深类之间的耦合,而这是OO系统所竭 力避免的
    3. 枝节性代码带来的耦合度会造成功能性代码移植困难,可重用性降低
    4. 从法理上说,枝节性代码应该`监视‘着功能性代码,然后采取行动,而不是功能性代码 `通知‘枝节性代码采取行动,这好比吟游诗人应该是主动记录骑士的功绩而不是骑士主 动要求诗人记录自己的功绩
  20. 常见的代理
  21. 毫无疑问,枝节性代码和功能性代码需要分开来才能降低耦合程度,符合现代OO系统的要 求,我们可以使用代理模式完成这个要求。

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

    1. 抽象角色:声明真实对象和代理对象的共同接口
    2. 代理角色:代理对象内部包含有真实角色的引用,从而可以操作真实角色,同时代理对象 与真实对象有相同的接口,能在任何时候代替真实对象,同时代理对象可以在执行真实对 象前后加入特定的逻辑以实现功能的扩展。
    3. 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象

    常见的代理有:

    1. 远程代理(Remote Proxy):对一个位于不同的地址空间对象提供一个局域代表对象,如RMI中的stub
    2. 虚拟代理(Virtual Proxy):根据需要将一个资源消耗很大或者比较复杂的对象,延迟加 载,在真正需要的时候才创建
    3. 保护代理(Protect or Access Proxy):控制对一个对象的访问权限。
    4. 智能引用(Smart Reference Proxy):提供比目标对象额外的服务和功能。

    通过代理类这一中间层,能够有效控制对实际委托类对象的直接访问,也可以很好地隐藏和 保护实际对象,实施不同的控制策略,从而在设计上获得了更大的灵活性。

  22. 动态代理:
  23. Dynamic Prox

    动态代理相比于静态代理,更具有灵活性

    动态代理不用显式地让它实现与真实主题类(RealSubject)相同的接口(interface),而是把这种实现推迟到运行时。

  24. 所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一 组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实 例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy, 它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工 作。
  25. 动态代理关联的API

    java.lang.reflect包下的类:

    InvocationHandler类:invoke(Object obj,Method method,Object[] objs)

    Proxy类:newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

  26. 一个典型的动态代理创建对象过程可分为以下三个步骤:

    1、通过实现InvocationHandler接口创建自己的调用处理器 InvocationHandler handler = new InvocationHandlerImpl(被代理对象);

    2、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入

    Interface inter= (Interface)newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

    3、通过Interface对象执行指定事物

    inter.method();

  27. 代理模式与装饰者模式的区别
  28. 代理模式和装饰者模式很像,在典型的例子上,如spring的AOP、远程代理类、JDK的proxy, 都是代理模式。JDK里的输入/输出器是很典型的装饰器模式!但在有些场景上,对设计模式 入门的新手,还是有点难区分,UML类图基本没区别,都是实现同一个接口,一个类包装另一 个类。 两者的定义:
    • 装饰器模式:能动态的新增或组合对象的行为
    • 代理模式:为其他对象提供一种代理以控制对这个对象的访问

    装饰模式是“新增行为”,而代理模式是“控制访问”。关键就是我们如何判断是“新增行 为”还是“控制访问”。你在一个地方写装饰,大家就知道这是在增加功能,你写代理,大 家就知道是在限制。

  29. 代理模式:在不改变接口的前提下,控制对象的访问

    例子:孙悟空扮演并代替高家三小姐

    孙悟空扮演高家三小姐,所以可以说孙悟空与高家三小姐具有共同的接口。如果猪八戒只想 见见高家三小姐的娇好面容,或者谈谈天说说地,那么高家三小姐的“代理”孙悟空是允许 的,但猪八戒想亲亲嘴,那么是不行的。这是保护代理模式的应用。只有代理对象认为合适 时,才会将客户端的请求传递给真实主题对象。

    装饰模式:在不改变接口的前提下,动态扩展对象的功能

    孙悟空有七十二般变化,在二郎神眼里,他永远是那只猢狲。装饰模式以对客户透明的方式 动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有 什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。他的每 一种变化都给他带来一种附加的本领。他变成鱼儿时,就可以到水里游泳;他变成雀儿时, 就可以在天上飞行。而不管悟空怎么变化,在二郎神眼里,他永远是那只猢狲。装饰模式以 对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在 装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能 加以扩展。

  30. 内省机制
  31. Ø定义:1.是java语言对Bean类属性、事件的一种缺省(=默认)的处理机制

    2.通过反射的方式操作JavaBean的属性

    例如Student类中有name属性,则可以通过反射机制调用getName和setName方法设置新值

    Ø补充:

    通过getName和setName方法访问name属性,这就是默认的规则,java的API中有提供访问bean的get和set

    方法的接口,都存于java.bean包下面

  32. 实现内省三步走
  33. 1.   Introspector的静态方法getBeanInfo,获取BeanInfo对象信息

    2.   通过BeanInfo对象调用getPropertyDescriptors获取PropertyDescriptor(bean的所有属性描述)

    3.   调用getWriteMethod和getReadMethod获取当前属性的get和set机制函数

  34. 技术归纳:

    properties文件

    java.util.Properties类

    类名.class.getResourceAsStream("文件路径");

    相关函数:

    load函数:加载properties文件

    getProperty函数:获取properties文件字段属性

  35. 一般的做法是通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。
  36. /**
     * 内省演示例子: 把某个对象的所有属性名称和值都打印出来
     */
    public class IntrospectorDemo {
     String name;
     String height;
        public static void main(String[] args) throws Exception{
            IntrospectorDemo demo = new IntrospectorDemo();
            demo.setName( "Winter Lau" );
            demo.setHeight(null);
            // 如果不想把父类的属性也列出来的话,
            // 那 getBeanInfo 的第二个参数填写父类的信息
            BeanInfo bi = Introspector.getBeanInfo(demo.getClass(), Object. class );
            PropertyDescriptor[] props = bi.getPropertyDescriptors();
            for ( int i=0;i<props.length;i++){
                System.out.println(props[i].getName()+ "=" +
                        props[i].getReadMethod().invoke(demo, null ));
            }
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this .name = name;
        }
     public String getHeight() {
      return height;
     }
     public void setHeight(String height) {
      this.height = height;
     }
    }
  37. Web开发框架Struts中的FormBean就是通过内省机制来将表单中的数据映射到类的属性上,因此要求FormBean的每个属性要有getter/setter方法。但也并不总是这样,什么意思呢?就是说对一个Bean类来讲,我可以没有属性,但是只要有getter/setter方法中的其中一个,那么Java的内省机制就会认为存在一个属性,比如类中有方法setMobile,那么就认为存在一个mobile的属性,这样可以方便我们把Bean类通过一个接口来定义而不用去关心具体实现,不用去关心 Bean中数据的存储。比如我们可以把所有的getter/setter方法放到接口里定义,但是真正数据的存取则是在具体类中去实现,这样可提高系统的扩展性。

    总结:

    将 Java 的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,例如我们前面提到的 Struts ,还有用于处理 XML 文件的 Digester 项目,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互结合方能发挥真正的智能化以及高度可扩展性。

时间: 2024-10-05 10:40:24

【Java笔记】Java——远程监控、反射、代理、内省机制的相关文章

Java笔记-Java 内存区域和GC机制

此次主要做一下java内存区域和GC机制的知识小结,下面的段落部分摘自网络,部分摘自书籍,具体的链接忘记了,因为这是之前学习的时候做下的笔记.还望原作者多多包涵! 1 Java垃圾回收 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.这是因为在Java虚拟机(JVM)中,存在自动内存管理和垃圾清扫机制.概括地说

Java笔记-Java相关概念和如何实现跨平台

一.Java相关概念 1.Java语言的核心特点跨平台面向对象 2.Java的历史版本JDK1.0,JDK1.1,JDK1.2....JDK5.0,JDK6.0,JDK7.0,JDK8.0 注意:JDK5.0是一个标志性的版本,该版本引入了很多新特性. 3.Java的分类Java从1.2开始,分为三个不同的分支 JavaSE(Java Standard Edition),Java标准版,专门用来开发桌面级应用JavaEE(Java Enterprise Edititon),Java企业版,专门开

14.5-全栈Java笔记:java.awt这些布局怎么写?|流式|边界|网格

布局管理器 读者会发现,如果使用坐标定位法(空布局),在一个比较复杂的界面上定位每个控件的坐标是一个非常麻烦的工作,而且在界面大小发生改变时,控件的绝对位置也不会随之发生改变.那么如果我们想让用户界面上的组件可以按照不同的方式进行排列怎么办?例如:可以依序水平排列,或者按网格方式进行排列等,其实每种排列方案都是指组件的一种"布局",要管理这些布局,就需要本节学习的布局管理器. 管理布局的类由java.awt包来提供,布局管理器是一组实现java.awt.LayoutManager接口的

12.7-全栈Java笔记:Java网络编程(五)

UDP通讯的实现 1.DatagramSocket:用于发送或接收数据包 当服务器要向客户端发送数据时,需要在服务器端产生一个DatagramSocket对象,在客户端产生一个DatagramSocket对象.服务器端的DatagramSocket将DatagramPacket发送到网络上,然后被客户端的DatagramSocket接收. DatagramSocket有两种构造函数.一种是无需任何参数的,常用于客户端.另一种需要指定端口,常用于服务器. 常用方法:send.receive. cl

12.4-全栈Java笔记:Java网络编程(二)

 基于TCP协议的Socket编程和通信 在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器.一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别. "请求-响应"模式: Socket类:发送TCP消息 ServerSocket类:创建服务器 套接字是一种进程间的数据交换机制.这些进程既可以在同一机器上,也可以在通过网络连接的不同机器上.换句话说,套接字起到通信端点的作用.

12.3-全栈Java笔记:Java网络编程(一)

Java为了可移植性,不允许直接调用操作系统,而是由java.net包来提供网络功能.Java虚拟机负责提供与操作系统的实际连接.  InetAddress 作用:封装计算机的IP地址和DNS(没有端口信息!). 特点:这个类没有构造函数.如果要得到对象,只能通过静态方法:getLocalHost.getByName. getAllByName. getAddress.getHostName. [示例1]使用getLocalHost方法创建InetAddress对象 InetAddress ad

11.2-全栈Java笔记:Java中如何实现多线程

在JAVA中使用多线程非常简单,我们先学习如何创建和使用线程,然后结合案例再深入剖析线程的特性. 通过继承Thread类实现多线程 继承Thread类实现多线程的步骤: 1. 在Java中负责线程的这个功能的是java.lang.Thread 这个类 2. 可以通过创建 Thread 的实例来创建新的线程. 3.  每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体. 4.   通过调用Thead类的start()方法来启动一个线程. [示

12.5-全栈Java笔记:Java网络编程(三)

上节回顾:在学习了Socket在建立客户端和服务器单项通讯中,分别创建独立的Socket,并通过Socket的属性. 那么如何将两个Socket进行连接,从而达到客户端和服务器之间建立输入输出流进行通信呢?在上节中我们已经讲到,TCP/IP套接字是最可靠的双向流协议,使用TCP/IP可以发送任意数量的数据.如果发送方和接收方计算机确定好端口,他们就可以通信了,其中的端口用套接字表示. [示例1]客户端与服务器端双向交流的Socket之服务器端 import java.io.BufferedRea

14.2-全栈Java笔记: Java Swing创建窗口,原来这么简单!!!

上节我们聊到GUI(Graphical User Interface)的概念,并学习GUI编程中主要需掌握两个包,分别是:AWT和Swing,本节我们会通过Swing程序中常用的类和控件来实现第一个窗口.  javax.swing.JFrame JFrame在GUI中为一个窗口对象,继承于Frame.JFrame控件用于在Swing程序中创建窗体.如表1所示,为JFrame常见的构造方法. 注意: Java语言规定在GUI编程中任何窗口实例化出来时默认为不可见(即隐藏)状态,所以当我们使用构造方

12.6-全栈Java笔记:Java网络编程(四)

上节回顾:在学习了Socket建立客户端和服务器双向交流后,我们发现它的问答形式不够灵活. 本节课我们讲解如何在服务器和客户端之间实现聊天室~ 需要思考的问题: 服务器端:一个线程专门发送消息,一个线程专门接收消息. 客户端:一个线程专门发送消息,一个线程专门接收消息. 除了消化这段代码外,还需要思考,怎么实现一个聊天室!(难度较大!!) [示例1]聊天室服务器端 import java.io.BufferedReader; import java.io.BufferedWriter; impo