zoukankan      html  css  js  c++  java
  • (四)Java学习-初步了解反射和动态代理

    “本文为传智大数据课程视频资料视频整理汇总”

    1 反射

        通过反射的方式可以获取class对象中的属性、方法、构造函数等

      1 package thread.reflect;
      2 
      3 import org.junit.Before;
      4 import org.junit.Test;
      5 
      6 import java.lang.reflect.Constructor;
      7 import java.lang.reflect.Field;
      8 import java.lang.reflect.Method;
      9 
     10 public class MyReflect {
     11 
     12     public String className = null;
     13     @SuppressWarnings("rawtypes")
     14     public Class personClass = null;
     15     /**
     16      * 反射Person类
     17      * @throws Exception
     18      */
     19     @Before
     20     public void init() throws Exception {
     21         className = "thread.reflect.Person";
     22         personClass = Class.forName(className);
     23     }
     24     /**
     25      *获取某个class文件对象
     26      */
     27     @Test
     28     public void getClassName() throws Exception {
     29         System.out.println(personClass);
     30     }
     31     /**
     32      *获取某个class文件对象的另一种方式
     33      */
     34     @Test
     35     public void getClassName2() throws Exception {
     36         System.out.println(Person.class);
     37     }
     38     /**
     39      *创建一个class文件表示的实例对象,底层会调用空参数的构造方法
     40      */
     41     @Test
     42     public void getNewInstance() throws Exception {
     43         System.out.println(personClass.newInstance());
     44     }
     45     /**
     46      *获取非私有的构造函数
     47      */
     48     @SuppressWarnings({ "rawtypes", "unchecked" })
     49     @Test
     50     public void getPublicConstructor() throws Exception {
     51         Constructor constructor  = personClass.getConstructor(Long.class,String.class);
     52         Person person = (Person)constructor.newInstance(100L,"zhangsan");
     53         System.out.println(person.getId());
     54         System.out.println(person.getName());
     55     }
     56     /**
     57      *获得私有的构造函数
     58      */
     59     @SuppressWarnings({ "rawtypes", "unchecked" })
     60     @Test
     61     public void getPrivateConstructor() throws Exception {
     62         Constructor con = personClass.getDeclaredConstructor(String.class);
     63         con.setAccessible(true);//强制取消Java的权限检测
     64         Person person2 = (Person)con.newInstance("zhangsan");
     65         System.out.println("**"+person2.getName());
     66     }
     67     /**
     68      *访问非私有的成员变量
     69      */
     70     @SuppressWarnings({ "rawtypes", "unchecked" })
     71     @Test
     72     public void getNotPrivateField() throws Exception {
     73         Constructor  constructor  = personClass.getConstructor(Long.class,String.class);
     74         Object obj = constructor.newInstance(100L,"zhangsan");
     75 
     76         Field field = personClass.getField("name");
     77         field.set(obj, "lisi");
     78         System.out.println(field.get(obj));
     79     }
     80     /**
     81      *访问私有的成员变量
     82      */
     83     @SuppressWarnings({ "rawtypes", "unchecked" })
     84     @Test
     85     public void getPrivateField() throws Exception {
     86         Constructor  constructor  = personClass.getConstructor(Long.class);
     87         Object obj = constructor.newInstance(100L);
     88 
     89         Field field2 = personClass.getDeclaredField("id");
     90         field2.setAccessible(true);//强制取消Java的权限检测
     91         field2.set(obj,10000L);
     92         System.out.println(field2.get(obj));
     93     }
     94     /**
     95      *获取非私有的成员函数
     96      */
     97     @SuppressWarnings({ "unchecked" })
     98     @Test
     99     public void getNotPrivateMethod() throws Exception {
    100         System.out.println(personClass.getMethod("toString"));
    101 
    102         Object obj = personClass.newInstance();//获取空参的构造函数
    103         Method toStringMethod = personClass.getMethod("toString");
    104         Object object = toStringMethod.invoke(obj);
    105         System.out.println(object);
    106     }
    107     /**
    108      *获取私有的成员函数
    109      */
    110     @SuppressWarnings("unchecked")
    111     @Test
    112     public void getPrivateMethod() throws Exception {
    113         Object obj = personClass.newInstance();//获取空参的构造函数
    114         Method method = personClass.getDeclaredMethod("getSomeThing");
    115         method.setAccessible(true);
    116         Object value = method.invoke(obj);
    117         System.out.println(value);
    118 
    119     }
    120     /**
    121      *
    122      */
    123     @Test
    124     public void otherMethod() throws Exception {
    125         //当前加载这个class文件的那个类加载器对象
    126         System.out.println(personClass.getClassLoader());
    127         //获取某个类实现的所有接口
    128         Class[] interfaces = personClass.getInterfaces();
    129         for (Class class1 : interfaces) {
    130             System.out.println(class1);
    131         }
    132         //反射当前这个类的直接父类
    133         System.out.println(personClass.getGenericSuperclass());
    134         /**
    135          * getResourceAsStream这个方法可以获取到一个输入流,这个输入流会关联到name所表示的那个文件上。
    136          */
    137         //path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
    138         System.out.println(personClass.getResourceAsStream("/log4j.properties"));
    139         System.out.println(personClass.getResourceAsStream("log4j.properties"));
    140 
    141         //判断当前的Class对象表示是否是数组
    142         System.out.println(personClass.isArray());
    143         System.out.println(new String[3].getClass().isArray());
    144 
    145         //判断当前的Class对象表示是否是枚举类
    146         System.out.println(personClass.isEnum());
    147         System.out.println(Class.forName("thread.reflect.City").isEnum());
    148 
    149         //判断当前的Class对象表示是否是接口
    150         System.out.println(personClass.isInterface());
    151         System.out.println(Class.forName("thread.reflect.MyInterface").isInterface());
    152 
    153 
    154     }
    155 
    156 }
    MyReflect

    使用反射进行socket调用

    业务接口

    1 package thread.reflect.socket;
    2 
    3 public interface Business {
    4     int getPrice(String goods);
    5 }
    View Code

    业务实现

    1 package thread.reflect.socket;
    2 
    3 public class BusinessImpl implements Business {
    4     @Override
    5     public int getPrice(String good) {
    6         return good.equals("clothes")?10:20;
    7     }
    8 }
    View Code

    服务端socket的处理类

     1 package thread.reflect.socket;
     2 
     3 import java.io.*;
     4 import java.lang.reflect.Method;
     5 import java.net.Socket;
     6 
     7 public class ServerTask implements Runnable{
     8     private Socket socket;
     9     public ServerTask(Socket socket){
    10         this.socket = socket;
    11     }
    12 
    13     @Override
    14     public void run() {
    15         InputStream in;
    16         OutputStream out;
    17         try {
    18             in = socket.getInputStream();
    19             out = socket.getOutputStream();
    20 
    21             BufferedReader br = new BufferedReader(new InputStreamReader(in));
    22             String request = br.readLine();
    23             String[] split = request.split(":");
    24             String className = split[0];
    25             String methodName = split[1];
    26             String methodParam= split[2];
    27 
    28             Class<?> forName = Class.forName(className);
    29             System.out.println("calling class: " + forName);
    30             Object newInstance = forName.newInstance();
    31             Method method = forName.getMethod(methodName,String.class);
    32             System.out.println("calling method: " + method);
    33             Object invoke = method.invoke(newInstance, methodParam);
    34             int value = Integer.parseInt(invoke.toString());
    35             System.out.println("results: " + value);
    36 
    37 
    38             PrintWriter pw = new PrintWriter(new BufferedOutputStream(out));
    39             pw.println(value);
    40             pw.flush();
    41 
    42             br.close();
    43             pw.close();
    44             socket.close();
    45 
    46         } catch (Exception e) {
    47 
    48             e.printStackTrace();
    49         }
    50 
    51     }
    52 
    53 }
    View Code

    服务端运行类

     1 package thread.reflect.socket;
     2 
     3 import java.net.InetSocketAddress;
     4 import java.net.ServerSocket;
     5 import java.net.Socket;
     6 
     7 public class Server {
     8     public static void main(String[] args) throws Exception {
     9         ServerSocket server = new ServerSocket();
    10         server.bind(new InetSocketAddress("localhost",9898));
    11         while(true){
    12             Socket socket = server.accept();
    13             new Thread(new ServerTask(socket)).start();
    14         }
    15     }
    16 }
    View Code

    客户端运行类

     1 package thread.reflect.socket;
     2 
     3 import java.io.*;
     4 import java.net.Socket;
     5 
     6 public class Client {
     7     public static void main(String[] args) throws Exception {
     8         Socket socket = new Socket("localhost", 9898);
     9         OutputStream out = socket.getOutputStream();
    10         InputStream in = socket.getInputStream();
    11 
    12         PrintWriter pw = new PrintWriter(new BufferedOutputStream(out));
    13         pw.println("thread.reflect.socket.BusinessImpl:getPrice:clothes");
    14         pw.flush();
    15 
    16         BufferedReader br = new BufferedReader(new InputStreamReader(in));
    17         String readLine = br.readLine();
    18 
    19         System.out.println("client get result: " + readLine);
    20 
    21         socket.close();
    22 
    23 
    24 
    25     }
    26 }
    View Code

    2 动态代理

            在之前的代码调用阶段,我们用action调用service的方法实现业务即可。

             由于之前在service中实现的业务可能不能够满足当先客户的要求,需要我们重新修改service中的方法,但是service的方法不只在我们这个模块使用,在其他模块也在调用,其他模块调用的时候,现有的service方法已经能够满足业务需求,所以我们不能只为了我们的业务而修改service,导致其他模块授影响。

             那怎么办呢?

             可以通过动态代理的方式,扩展我们的service中的方法实现,使得在原有的方法中增加更多的业务,而不是实际修改service中的方法,这种实现技术就叫做动态代理。

             动态代理:在不修改原业务的基础上,基于原业务方法,进行重新的扩展,实现新的业务。

             例如下面的例子:

     1、  旧业务

     买家调用action,购买衣服,衣服在数据库的标价为50元,购买流程就是简单的调用。

     2、  新业务

     在原先的价格上可以使用优惠券,但是这个功能在以前没有实现过,我们通过代理类,代理了原先的接口方法,在这个方法的基础上,修改了返回值。

             代理实现流程:

     1、  书写代理类和代理方法,在代理方法中实现代理Proxy.newProxyInstance

     2、  代理中需要的参数分别为:被代理的类的类加载器soneObjectclass.getClassLoader(),被代理类的所有实现接口new Class[] { Interface.class },句柄方法new InvocationHandler()

     3、  在句柄方法中复写invoke方法,invoke方法的输入有3个参数Object proxy(代理类对象), Method method(被代理类的方法),Object[] args(被代理类方法的传入参数),在这个方法中,我们可以   定制化的开发新的业务。

     4、  获取代理类,强转成被代理的接口

     5、  最后,我们可以像没被代理一样,调用接口的认可方法,方法被调用后,方法名和参数列表将被传入代理类的invoke方法中,进行新业务的逻辑流程。

     

    IBoss业务接口定义类

    1 package thread.proxy.bossProxy;
    2 
    3 public interface IBoss {
    4     int sales(String size);
    5 
    6     String giveBack(String size);
    7 }
    View Code

           Boss业务接口实现类

     1 package thread.proxy.bossProxy;
     2 
     3 public class Boss implements IBoss{
     4 
     5     @Override
     6     public int sales(String size) {
     7         System.err.println("天猫小强旗舰店衣服A大小:"+size);
     8         //这件衣服的价钱,从数据库读取
     9         return 50;
    10     }
    11 
    12     @Override
    13     public String giveBack(String size) {
    14         return "退货退货";
    15     }
    16 }
    View Code

           Boss业务调用类

     1 package thread.proxy.bossProxy;
     2 
     3 import org.junit.Test;
     4 
     5 public class SalesAction {
     6     /**
     7      * 不使用代理,直接调用方法
     8      * 方法中规定什么业务,就只能调用什么业务,规定什么返回值,就只能输出什么返回值
     9      */
    10     @Test
    11     public void saleByBossSelf() throws Exception {
    12         IBoss boss = new Boss();
    13         System.out.println("老板自营!");
    14         int money = boss.sales("xxl");// 老板自己卖衣服,不需要客服,结果就是没有聊天记录
    15         System.out.println("衣服成交价:" + money);
    16     }
    17 }
    View Code

          代理Boss业务实现类

     1 package thread.proxy.bossProxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 
     7 public class ProxyBoss {
     8 
     9     @SuppressWarnings("unchecked")
    10     public static <T> T getProxy(final int discountCoupon,final Class<?> interfaceClass, final Class<?> implementsClass)
    11             throws Exception {
    12         return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
    13                 new Class[] { interfaceClass }, new InvocationHandler() {
    14                     public Object invoke(Object proxy, Method method,
    15                                          Object[] args) throws Throwable {
    16                         Integer returnValue = (Integer) method.invoke(
    17                                 implementsClass.newInstance(), args);// 调用原始对象以后返回的值
    18                         return returnValue - discountCoupon;
    19                     }
    20                 });
    21     }
    22 }
    View Code

         代理Boss业务调用类

     1 package thread.proxy.bossProxy;
     2 
     3 import org.junit.Test;
     4 
     5 public class ProxySalesAction {
     6 
     7     @Test
     8     public void saleByProxy() throws Exception {
     9         IBoss boss = ProxyBoss.getProxy(10,IBoss.class,Boss.class);// 将代理的方法实例化成接口
    10         System.out.println("代理经营!");
    11         int money = boss.sales("xxl");// 调用接口的方法,实际上调用方式没有变
    12         System.out.println("衣服成交价:" + money);
    13     }
    14 
    15 }
    View Code
  • 相关阅读:
    当框架限制了我的想法,我选择Hack
    Ubuntu下自制douban.fm播放器
    如何让基于Swing的Java程序在Linux下看起来更和谐
    基于Bootstrap的黑色极简博客园主题
    spring boot引入外部jar包
    Spring缓存注解@CachePut , @CacheEvict,@CacheConfig使用
    【转】c#如何监视文件或者文件夹的变化
    【转】一些重要的计数器
    【原创】使用timer、imagelist与notifyicon控件实现图标闪烁并避免了GDI泄漏(重点)
    【转】全角字符与半角字符的相互转换(C#)
  • 原文地址:https://www.cnblogs.com/zzzmublog/p/11290452.html
Copyright © 2011-2022 走看看