# 反射机制

反射是Java语言的一项重要技术,将类的各个组成部分封装为其他对象,然后再操作这些对象,利用反射可以解耦,使用它们可进一步提升代码重用性和可扩展性,注意重用性是面向对象设计的核心原则。反射涉及两种操作:

  • 正:由类实例化成对象,使用对象来调用方法。
  • 反:根据实例化对象来推出其类。

下面是三种获取Class类实例的方式:

class MyInfo{
    
}
public class Main {
    public static void main(String[] args) {
        //使用getClass()方法获取实例对象。常用于由对象获取字节码。
        MyInfo myInfo = new MyInfo();
        Class<?> myClass = myInfo.getClass();
        System.out.println(myClass);

        //使用类名,利用JVM支持。常用于参数的传递。
        Class<?> myClass2 = MyInfo.class;
        System.out.println(myClass2);

        //使用forName()。常用于配置文件,将类定义在配置文件中。
        try {
            Class<?> myClass3 = Class.forName("MyInfo");
            System.out.println(myClass3);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

注意不论以什么形式加载,同一字节码文件(.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。

# 反射实例化

反射实例化对象可以帮助程序摆脱对关键字new的依赖,通过反射获取实例化对象。

class MyInfo {
    public MyInfo() {
        System.out.println("this is myInfo class");
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "this is my Info!";
    }
}

public class Main {
    public static void main(String[] args) throws Exception {

        try {
            Class<?> myClass = Class.forName("MyInfo");
            // 在JDK 1.9之后提倡这样做,在JDK 1.9之前可使用newInstance
            Object myInfo2 = myClass.getDeclaredConstructor().newInstance();
            //简化样式如下:
            Object myInfo3 = myClass.newInstance();
            System.out.println(myInfo2);
            System.out.println(myInfo3);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 反射与工厂设计模式

工厂的主要目标是解决接口与子类之间的因使用new关键字所造成的耦合问题,传统的工厂设计操作有两个严重的问题:

  • 传统工厂属于静态工厂设计,需要结合大量的分支语句来判断所需要实例化的子类,当一个接口或抽象类扩充子类时必须修改工厂结构。
  • 工厂设计能满足一个接口或抽象类获取实例化对象的需求,如果有更多接口或抽象类时需要定义更多的工厂类。

下面使用反射来完成工厂设计模式:


interface IClient {
    public void SendInfo();
}

class AndroidPhone implements IClient {

    @Override
    public void SendInfo() {
        // TODO Auto-generated method stub
        System.out.println("android phone is instanced!");

    }

}

class IPhone implements IClient {

    @Override
    public void SendInfo() {
        // TODO Auto-generated method stub
        System.out.println("iphone is instanced!");
    }

}

class PC implements IClient {

    @Override
    public void SendInfo() {
        // TODO Auto-generated method stub
        System.out.println("pc is instanced!");
    }
}

class ClientFactory {
    public static <T> T GetInstance(String className, Class<T> class1) {
        T instanceT = null;
        try {
            instanceT = (T) Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            // TODO: handle exception
            System.err.println(e);
        }
        return instanceT;

    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        IClient myClient = ClientFactory.GetInstance("IPhone", IClient.class);
        myClient.SendInfo();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 反射与单例设计模式

单例设计模式的本质在于,私有化类的构造方法,在类内部产生实例化对象后通过静态方法把实例给外部。设计模式一共有两类:懒汉式和饿汉式,饿汉式的单例在类加载时就已经进行了对象实例化处理,所以不涉及多线程的访问,懒汉式的单例在多线程访问下可能会出现多个实例化对象,比如下面:

class Singleton{
    private static Singleton instance = null;
    private Singleton() {
        System.out.println(Thread.currentThread().getName()+":"+this);
    }
    
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        for(int i=0;i<10;i++) {
            new Thread(()->{
                Singleton.getInstance();
            },"线程"+i).start();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

上面发现不同的线程会创建不同的实例,使用同步机制及反射来解决这个问题:

class Singleton {
    private static Singleton instance = null;

    private Singleton() {
        System.out.println(Thread.currentThread().getName() + ":" + this);
    }

    public static Singleton getInstance() {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Singleton.getInstance();
            }, "线程" + i).start();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 类操作

Java反射机制可在程序运行状态下自动获取并调用任意一个类的成员属性或方法,可让程序调用更灵活,它的类结构如下:

reflectClassOper

注意下面获取类的属性或方法使用getDeclaredXXX与getXXX的区别是后者只能获取public属性或方法。

# 获取类结构信息

package my.tools;

interface IClient {
    public void SendInfo();
}
interface IReceive{
    public void ReceiveInfo();
}

class AndroidPhone implements IClient,IReceive {

    @Override
    public void SendInfo() {
        // TODO Auto-generated method stub
        System.out.println("android phone is instanced!");
    }

    @Override
    public void ReceiveInfo() {
        // TODO Auto-generated method stub
        System.out.println("接收信息!");
    }
}



public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> androidPhoneClass = AndroidPhone.class;
        System.out.println("类名为:"+androidPhoneClass.getName());
        System.out.println("包名为:"+androidPhoneClass.getPackageName());
        System.out.println("包名2为:"+androidPhoneClass.getPackage().getName());
        System.out.println("父类名为:"+androidPhoneClass.getSuperclass().getName());
        //System.out.println("父类的父类名为:"+androidPhoneClass.getSuperclass().getSuperclass().getName());
        Class<?> myInterfaces[] = androidPhoneClass.getInterfaces();
        for(Class<?> temp:myInterfaces) {
            System.out.println(temp.getName());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 调用构造方法

import java.lang.reflect.Constructor;

class MyClassReflect{
    String msgString;
    public MyClassReflect() {
        System.out.println("none parameter constructor!");
    }
    
    public MyClassReflect(String str) {
        msgString = str;
    }
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return msgString;
    }
    
}
public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> MyClass = MyClassReflect.class;
        Constructor<?>[] constructors = MyClass.getDeclaredConstructors();
        for(Constructor<?> cons : constructors) {
            System.out.println(cons);
        }
        
        Constructor<?> cons = MyClass.getDeclaredConstructor(String.class);
        Object object = cons.newInstance("hello world!");
        System.out.println(object);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 反射调用方法

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

class MyClassReflect {
    private String nameString;
    private int age;

    public String getNameString() {
        return nameString;
    }

    public void setNameString(String nameString) {
        this.nameString = nameString;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String receive() throws IOException, Exception {
        System.out.println("receive info!");
        return "receive";
    }

    public int Send() {
        System.out.println("send info!");
        return 10;
    }

}

public class Main {
    public static void GetMethodInfo() {
        Class<?> MyClass = MyClassReflect.class;
        Method methods[] = MyClass.getMethods();
        for (Method met : methods) {
            int modifier = met.getModifiers();
            System.out.print(Modifier.toString(modifier) + " ");
            System.out.print(met.getReturnType().getName() + " ");
            System.out.print(met.getName() + "(");

            Class<?> params[] = met.getParameterTypes();
            for (int i = 0; i < params.length; i++) {
                System.out.print(params[i].getName() + " " + "arg" + i);
                if (i < params.length - 1) {
                    System.out.print(",");
                }
            }
            System.out.print(")");
            Class<?> exp[] = met.getExceptionTypes();
            if (exp.length > 0) {
                System.out.print(" throws ");
            }
            for (int i = 0; i < exp.length; i++) {
                System.out.print(exp[i].getName());
                if (i < exp.length - 1) {
                    System.out.print(",");
                }
            }
            System.out.println();
        }
    }

    public static void RunObject() {
        Class<?> MyClass = MyClassReflect.class;
        try {
            Object object = MyClass.getDeclaredConstructor().newInstance();
            Method setMethod = MyClass.getDeclaredMethod("setAge", int.class);
            setMethod.invoke(object, 100);
            Method getMethod = MyClass.getDeclaredMethod("getAge");
            System.out.println(getMethod.invoke(object));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static void main(String[] args) throws Exception {
        GetMethodInfo();
        RunObject();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

# 反射调用属性

import java.lang.reflect.Field;

interface ICommonInfo {
    public static final String NAME = "li";
}

abstract class AbstractClass {
    protected static final String Sex = "man";
    private String infoString = "math";
}

class MyClass extends AbstractClass implements ICommonInfo {
    private int score = 100;
    public int rank = 50;
    protected float average = 78;

}

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> myClass = MyClass.class;
        // 获取所有公共成员属性
        {
            Field fields[] = myClass.getFields();
            for (Field oneField : fields) {
                System.out.println(oneField);
            }
        }

        System.out.println("----------------------");
        // 只获取本类属性
        {
            Field fields[] = myClass.getDeclaredFields();
            for (Field oneField : fields) {
                System.out.println(oneField);
            }
        }
        //获取对象属性
        {
            Object object = myClass.getDeclaredConstructor().newInstance();
            Field scoreField = myClass.getDeclaredField("score");
            scoreField.setAccessible(true);
            scoreField.set(object, 200);
            System.out.println(scoreField.get(object));
            //获取score字段的类型
            System.out.println(scoreField.getType().getName());
            System.out.println(scoreField.getType().getSimpleName());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# Unsafe工具类

Java中提供了一个sun.misc.Unsafe类,它的特点是可以利用反射来获取对象,直接使用底层的C++语言来代替JVM执行,可以绕过JVM的对象管理机制,一旦使用了Unsafe类,项目中将无法使用JVM的内存管理机制以及垃圾回收处理。

import java.lang.reflect.Field;
import sun.misc.Unsafe;

class MySingleton {
    private MySingleton() {
    }

    public void GetInfo() {
        System.out.println("this is my info!");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Field  field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafeObject = (Unsafe) field.get(null);
        MySingleton instance = (MySingleton)unsafeObject.allocateInstance(MySingleton.class);
        instance.GetInfo();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 反射应用

当我们创建一个对象实例时,如果该对象有很多属性,那样会有很多的setter,getter方法,这样代码重复度会很高,如果使用反射的话会简化这个流程。

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

class SchoolInfo {
    private String schoolName;


    public String getSchoolName() {
        return schoolName;
    }


    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }


    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "schoolName:" + schoolName;
    }

}

class ClassInfo {
    private String className;
    private SchoolInfo schoolInfo;

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public SchoolInfo getSchoolInfo() {
        return schoolInfo;
    }

    public void setSchoolInfo(SchoolInfo schoolInfo) {
        this.schoolInfo = schoolInfo;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "className:" + className + "\nschoolInfo:" + schoolInfo + "\n";
    }
}

class PersonInfo {
    private String name;
    private int age;
    private ClassInfo classInfo;
    private Date birthday;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public ClassInfo getClassInfo() {
        return classInfo;
    }

    public void setClassInfo(ClassInfo classInfo) {
        this.classInfo = classInfo;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "name:" + name + "\nage:" + age + "\nbirthday:" + birthday + "\nclassInfo:" + classInfo + "\n";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

class CreateClassByReflect {
    public static <T> T Create(Class<?> targetClass, String attributes) {
        Object object = null;
        try {
            object = targetClass.getDeclaredConstructor().newInstance();
            SetValue(object, attributes);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return (T) object;
    }

    public static void SetValue(Object object, String attributeString) {
        String fieldStrs[] = attributeString.split("\\|");
        for (int i = 0; i < fieldStrs.length; i++) {
            String attrKeyValue[] = fieldStrs[i].split(":");
            String attrName[] = attrKeyValue[0].split("\\.");
            if (attrName.length > 1) {
                Object parentObj = object;
                for (int j = 0; j < attrName.length - 1; j++) {
                    try {
                        String currentClassName = attrName[j];
                        Method getMethod = parentObj.getClass()
                                .getDeclaredMethod("get" + InitFirstLetter(currentClassName));

                        if (getMethod.invoke(parentObj) == null) {
                            Field field = parentObj.getClass().getDeclaredField(currentClassName);
                            Class<?> targetClass = Class.forName(field.getType().getName());
                            Object subObject = targetClass.getDeclaredConstructor().newInstance();
                            Method setMethod = parentObj.getClass()
                                    .getDeclaredMethod("set" + InitFirstLetter(currentClassName), field.getType());
                            setMethod.invoke(parentObj, subObject);
                            parentObj = subObject;
                        } else {
                            parentObj = getMethod.invoke(object);
                        }

                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
                try {
                    String attributeName=attrName[attrName.length - 1];
                    Field field = parentObj.getClass().getDeclaredField(attributeName);
                    Method setMethod = parentObj.getClass()
                            .getDeclaredMethod("set" + InitFirstLetter(attributeName), field.getType());
                    setMethod.invoke(parentObj, convertValueType(field.getType().getName(), attrKeyValue));
                } catch (Exception e) {
                    // TODO: handle exception
                    System.out.println(e);
                }

            } else {
                try {
                    Field field = object.getClass().getDeclaredField(attrKeyValue[0]);
                    Method setMethod = object.getClass().getDeclaredMethod("set" + InitFirstLetter(attrKeyValue[0]),
                            field.getType());
                    setMethod.invoke(object, convertValueType(field.getType().getName(), attrKeyValue));
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public static String InitFirstLetter(String str) {
        if (str == null || "".equals(str)) {
            return str;
        }
        if (str.length() == 1) {
            return str.toUpperCase();
        } else {
            return str.substring(0, 1).toUpperCase() + str.substring(1);
        }
    }

    public static Object convertValueType(String type, String[] values) {
        String value = null;

        if ("java.util.Date".equals(type)) {
            if (values.length == 4) {
                value = values[1] + ":" + values[2] + ":" + values[3];
            }
            SimpleDateFormat simpleDateFormat = null;
            if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
                simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            } else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
                simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            } else {
                return new Date();
            }
            try {

                return simpleDateFormat.parse(value);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                return new Date();
            }
        } else {
            value = values[1];
        }
        if ("int".equals(type) || "java.lang.Integer".equals(type)) {
            return Integer.parseInt(value);
        }
        if ("long".equals(type) || "java.lang.Long".equals(type)) {
            return Long.parseLong(value);
        }
        if ("double".equals(type) || "java.lang.Double".equals(type)) {
            return Double.parseDouble(value);
        }

        return value;
    }

}

public class Main {

    public static void main(String[] args) throws Exception {
        String attributeString = "name:xie|age:30|birthday:2020-01-01 12:30:15|classInfo.schoolInfo.schoolName:someSchool|classInfo.className:class1";
        PersonInfo myClass = CreateClassByReflect.Create(PersonInfo.class, attributeString);
        System.out.println("------------------");
        System.out.println(myClass);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

# ClassLoader类加载器

Java程序执行需要JVM,JVM执行类时会通过CLASSPATH所指定的路径字节码文件加载,而JVM加载字节码文件的操作需要使用到类加载器(ClassLoader)。

它们的流程如下:

classLoader

# 类加载器

JVM解释的程序类需要通过类加载器进行加载后才可以执行,为了保证Java程序执行的安全性,JVM提供3种类加载器:

  • Bootstrap(根加载器,又称系统加载器):由C++编写的类加载器,是Java虚拟机启动后进行初始化操作,主要目的是加载Java底层系统核心类库。
  • PlatformClassLoader(类加载器,平台类加载器):JDK 1.8以前为ExtClassLoader,使用Java编写的类加载器,主要对模块进行加载。
  • AppClassLoader(应用程序类加载器):加载CLASSPATH所指定的类文件或JAR文件。

classLoaderClassify

Java为什么要提供3中类加载器?

Java装载类时使用的是"全局负责委托机制":

  • 全局负责:使用一个ClassLoader进行类加载时,除非显式地使用其他类加载器,该类所依赖及引用的类也会用同样的ClassLoader进行加载。
  • 责任委托:先委托父类加载器进行加载,找不到父类时才由自己负责加载,类不会被重复加载。

这样当有一个伪造系统类时,比如说伪造java.lang.String,利用该机制就会保证java.lang.String永远都是由Bootstrap类加载器加载,保证了系统的安全。

class MyClass{
}
public class Main {
    public static void main(String[] args) throws Exception {
        String string="hello world!";
        //Bootstrap根加载器不是由Java编写,只能以null形式返回。
        System.out.println(string.getClass().getClassLoader());
        MyClass myClass = new MyClass();
        System.out.println(myClass.getClass().getClassLoader());
        System.out.println(myClass.getClass().getClassLoader().getParent());
        System.out.println(myClass.getClass().getClassLoader().getParent().getParent());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 自定义ClassLoader

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

class MyClassLoader extends ClassLoader {
    public Class<?> loadData(String className) throws Exception {
        byte[] data = null;
        InputStream inputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            inputStream = new FileInputStream(new File(className + ".class"));
            inputStream.transferTo(byteArrayOutputStream);
            data = byteArrayOutputStream.toByteArray();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (byteArrayOutputStream != null) {
                byteArrayOutputStream.close();
            }
        }
        if (data != null) {
            return super.defineClass(className, data, 0, data.length);
        }
        return null;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        MyClassLoader myClassLoader = new MyClassLoader();
        Class<?> cls = myClassLoader.loadData("MyClass");
        Object obj = cls.getDeclaredConstructor().newInstance();
        java.lang.reflect.Method method = cls.getDeclaredMethod("PrintInfo");
        method.invoke(obj);
        System.out.println(cls.getClassLoader());
        System.out.println(cls.getClassLoader().getParent());
        System.out.println(cls.getClassLoader().getParent().getParent());
        System.out.println(cls.getClassLoader().getParent().getParent().getParent());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 反射与代理设计模式

代理设计模式可以有效地将真实业务与代理业务之间的拆分,让开发者更专注地实现核心业务。注意基础代理设计模式中,每一个代理类需为一个真实业务类服务,如果项目中有3000个接口,会创建3000个重复的代理类,这时就需要反射发挥作用。要给功能相近的类提供统一的代理支持,要求定义一个公共代理类,Java针对此类代理类提供了一个公共的标准接口:java.lang.reflect.InvocationHandler。还需要在运行中被代理类所实现的接口动态地创造一个临时的代理对象。可通过java.lang.reflect.Proxy来实现。

基础代理设计模式:

baseProxy

使用Proxy实现代理设计模式:

proxyProxy

下面使用Proxy来实现代理设计模式:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


interface IStartOper{
    public void StartOper(String oper1);
}

class ComputerOper implements IStartOper{

    @Override
    public void StartOper(String oper1) {
        // TODO Auto-generated method stub
        System.out.println("电脑启动!"+oper1);
    }
}

class DeviceOper implements InvocationHandler{
    private Object target;
    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    
    public void Oper1(){
        System.out.println("Oper1!");
    }
    
    public void Oper2() {
        System.out.println("Oper2!");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object returnData = null;
        returnData = method.invoke(this.target, args);
        Oper1();
        Oper2();
        return returnData;
    }
    
}

public class Main {
    public static void main(String[] args) throws Exception {
        IStartOper startOper = (IStartOper)new DeviceOper().bind(new ComputerOper());
        startOper.StartOper("测试");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# CGLIB代理设计模式

上面的代理设计模式是基于接口的,官方给出的Proxy类创建代理对象时都需要传递该对象的所有接口信息。有些人认为不应该强迫性地基于接口实现代理设计,这样就有了一个第三方的包CGLIB,它可以实现基于类的代理设计模式。

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

class ComputerOper {

    public void StartOper(String oper1) {
        // TODO Auto-generated method stub
        System.out.println("电脑启动!"+oper1);
    }
}

class DeviceOperProxy implements MethodInterceptor{
    private Object target;
    public DeviceOperProxy(Object target) {
        this.target = target;
    }
    
    public void Oper1(){
        System.out.println("Oper1!");
    }
    
    public void Oper2() {
        System.out.println("Oper2!");
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // TODO Auto-generated method stub
        Object returnData = null;
        returnData = method.invoke(this.target, args);
        Oper1();
        Oper2();
        return returnData;
    }
    
}

public class Main {
    public static void main(String[] args) throws Exception {
        ComputerOper computerOper = new ComputerOper();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(computerOper.getClass());
        enhancer.setCallback(new DeviceOperProxy(computerOper));
        ComputerOper computerOper2 = (ComputerOper)enhancer.create();
        computerOper2.StartOper("cglib代理!");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50