(四)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
原文地址:https://www.cnblogs.com/zzzmublog/p/11290452.html