在学习 Spring 框架的 AOP(面向切面编程)过程中,发现其实现原理就是 动静代理模式 和反射。
反射:
将类的各个组成部分封装成其余对象。(成员变量、构造方法、成员办法)
-
益处
- 在程序运行过程中,能够操作这些对象实现一些操作。
- 能够对程序进行解耦,进步程序的可扩展性。
反射的应用:
获取 Class 对象:
获取 Class 对象的起因:当你要应用反射机制去操作这些封装对象的时候,首先是要获取到字节码 Class 对象
获取 Class 对象的形式:
- Class.forName(“ 全类名 ”):将字节码文件加载进内存,返回 Class 对象(个别用在配置文件,将类名定义在配置文件外面。读取文件)
- 类名.class:通过类名的属性 class 获取
- 对象.getClass():getClass()办法在 object 类中定义(个别用于曾经有一个对象,想获取它的字节码)
Class 对象性能:
获取成员变量:
1. Field[] getFields() // 获取所有 public 润饰的成员变量
2. Field getField(String name) // 获取指定名称的 public 润饰的成员变量
3. Field[] getDeclaredFields() // 获取所有的成员变量,不思考修饰符
4. Field getDeclaredFields(String name) // 获取指定名称的成员变量,不思考修饰符
Field: 成员变量
操作:1. 设置值:void set(Object obj,Object value)
2. 获取值
get(Object obj)
3. 疏忽拜访权限修饰符的安全检查
setAccessible(true):暴力反射
获取构造方法:
1. Constructor<?>[] getConstrucors() // 获取 public 润饰无参构造方法
2. Constructor<T>[] getConstrucors(类 <?>...parameterTypes)// 获取指定参数的 public 润饰有参构造方法
3. Constructor<T>[] getDeclaredConstrucors(类 <?>...parameterTypes)// 获取所有的指定参数类型的有参构造方法
4. Constructor<?>[] getDeclaredConstrucors()// 获取所有有参构造方法
Constructor: 构造方法
T newInstance(Object... initargs)
获取成员办法:
1. Method[] getMethods()
2. Method getMethod(String name, 类 <?>...parameterTypes)
3. Method getDeclaredMethods()
4. Method getDeclaredMethod(String name, 类 <?>...parameterTypes)
Method: 办法对象
执行办法:Object invoke(Object obj,Object...args)
获取办法名称:String getName:获取办法名
例子:
根本办法:
首先轻易创立一个类
package com.yuan.bean;
public class Person {
private String name;
public Integer age;
public Person() {}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
@Override
public String toString() {
return "Person{" +
"name='" + name + '''+", age="+ age +'}';
}
public void eat(){System.out.println("干饭");
}
}
接下来通过下面介绍的办法,综合起来使用一下:
public class test01 {public static void main(String[] args) throws Exception { // 办法中可能呈现多处异样,先抛个大的异样
// 获取 Class 类对象
Class cls = Class.forName("com.yuan.bean.Person");
/*
其余两种办法
Class<Person> personClass = Person.class;
Person p = new Person(); Class cls = p.getClass();
*/
// 获取类成员变量
Field[] fields = cls.getFields();
for(Field filed:fields){System.out.println(filed.getType()+" "+filed.getName()); //class java.lang.Integer age
}
// 获取类构造方法
Constructor constructor = cls.getConstructor();
Person o = (Person) constructor.newInstance();// 通过结构器的 newInstance()创立 Person 类对象
// 获取类成员办法
Method method = cls.getMethod("eat");
method.invoke(o);// 通过 method 的 invoke()办法调用成员办法 /* 干饭 */}
}
写一个“框架”, 能够帮咱们创立任意类的对象,并且执行其中任意办法:(能够练个手)
1. 首先在 src 目录下创立一个 properties 配置文件:
(外面放咱们要创建对象的类门路,以及要调用的类办法)
className=com.yuan.bean.Person
methodName=eat
2. 编写测试方法
public class ReflectTest {public static void main(String[] args) throws Exception {
// 加载配置文件
Properties pro = new Properties();// 创立 Properties 对象
ClassLoader classLoader = ReflectTest.class.getClassLoader();// 通过类对象 获取类加载器 getClassLoader()
InputStream is = classLoader.getResourceAsStream("pro.properties");// 通过类加载器获取配置文件的字节输出流对象
pro.load(is);// 加载文件
// 获取配置文件中加载的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 加载该类进内存,获取 Class 类对象
Class cls = Class.forName(className);
// 获取构造方法
Constructor constructor = cls.getConstructor();
// 通过构造方法创建对象
Object o = constructor.newInstance();
// 获取成员办法
Method method = cls.getMethod(methodName);
// 调用成员办法
method.invoke(o);
}
}
后续:
这些也只是根本总结了反射的基本概念和办法,通过反射,咱们能够不通过 new 的形式去创立一个新的对象,能够通过反射获取一个类的成员变量、构造方法、成员办法。能够通过操作一个类,去通过获取到的类的构造方法来创建对象,以及调用类的成员办法,批改类的成员变量的值。
在学习 Spring 框架中,AOP 使用到了 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现动静代理。所以对于反射概念的相熟是非常有必要的。