Spring IOC——Java反射
1 基础
spring的技术核心之一是动态代理
,而动态代理的核心是java反射
。所以如果要学习spring框架,java反射是我们永远也绕不开的一个坎,这是基础。
2 反射定义
反射被视为动态语言的关键,java反射机制是在运行状态中
,对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象
,都能够调用它的任意方法和属性
这种动态获取信息
以及动态调用对象方法
的功能称为java语言的反射机制。
3 反射概述
Class类
与java.lang.reflect类库
一起对反射的概念进行了支持,该类库中包含了Field
、Method
和Constructor
类(每个类都实现了Member接口)。
这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。
这样就可以使用Constructor创建新的对象
,用get()
和set()
方法读取
和修改
与Field对象
关联的字段
用invoke()
方法调用与Method对象关联的方法
。
另外,还可以调用getFields()
、getMethod()
和getConstructor()
等方法,返回表示字段
、方法
和构造器
的对象数组
。这样匿名对象的类信息就能在运行时
被完全确定下来,而在编译时
不需要知道任何事情。
4 反射示例
4.1 如何获取Class(加载一次)实例
- 运行时类本身的
.class
属性,如:Student.class - 通过运行时类的对象获取,如:
student.getClass()
- 通过Class的静态方法获取,如:
Class.forName("model.reflect.Student")
- 通过类的加载器,如:
classLoader.loadClass("model.reflect.Student");
Student类
public class Student {
private String name;
private String id;
public Student() {
}
public Student(String name,String id) {
this.id = id;
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
private String show(int index) {
String show = null;
switch (index){
case 0:
show = "我这样show";
break;
case 1:
show = "我那样show";
break;
default:
show = "我按平常show";
}
return show;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
}
反射测试类
public class StudentTest {
//反射公有方法
public static void reflectPublicMethod() throws Exception{
Class<?> aClass = Class.forName("model.reflect.Student");
Method setName = aClass.getMethod("setName", String.class);
Method setId = aClass.getMethod("setId", String.class);
//通过Class获取对象的实例时,需要空的构造方法,权限也要足够
Object student = aClass.newInstance();
setName.invoke(student, "fjx");
setId.invoke(student, "20173106666");
System.out.println("反射公有方法");
System.out.println(student);
}
public static void main(String[] args) throws Exception {
reflectPublicMethod();
}
}
public class StudentTest {
//反射定制的构造方法
public static void reflectConstructor() throws Exception{
Class<?> aClass = Class.forName("model.reflect.Student");
Constructor<?> constructor = aClass.getConstructor(String.class, String.class);
Object student = constructor.newInstance("fjx","20173106666");
System.out.println("反射定制的构造方法");
System.out.println(student);
}
public static void main(String[] args) throws Exception {
reflectConstructor();
}
}
反射私有方法(私有成员变量也大同小异)
public class StudentTest {
//反射私有方法
public static void reflectPrivateMethod() throws Exception {
Class<?> aClass = Class.forName("model.reflect.Student");
//注意使用getDeclaredMethod()方法,可以得到私有方法,得到私有属性使用getDeclaredField()
//getMethod()只能得到公有方法
Method show = aClass.getDeclaredMethod("show", int.class);
//如果没有设置为true,就不能访问私有的方法或变量,抛出java.lang.IllegalAccessException
show.setAccessible(true);
Object student = aClass.newInstance();
String showDes = (String)show.invoke(student,1);
System.out.println("反射私有方法");
System.out.println(showDes);
}
public static void main(String[] args) throws Exception {
reflectPrivateMethod();
}
}
错误演示
正确演示
5 反射相关类及相应方法
5.1 相关类
类名 | 用途 |
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
5.1.1 Class类
- 获得类相关方法
方法 | 用途 |
asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 |
cast | 把对象转换成代表类或是接口的对象 |
getClassLoader() | 获得类的加载器 |
getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 |
forName(String className) | 根据类名返回类的对象 |
getName() | 获得类的完整路径名字 |
newInstance() | 创建类的实例 |
getPackage() | 获得类的包 |
getSimpleName() | 获得类的名字 |
getSuperclass() | 获得当前类继承的父类的名字 |
getInterfaces() | 获得当前类实现的类或是接口 |
- 获得类中属性相关方法
方法 | 用途 |
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
- 获得类类中注解相关的方法
方法 | 用途 |
getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() | 返回该类所有的公有注解对象 |
getDeclaredAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() | 返回该类所有的注解对象 |
- 获得类中构造器相关的方法
方法 | 用途 |
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
- 获得类中方法相关的方法
方法 | 用途 |
getMethod(String name, Class…<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
- 类中其他重要的方法
方法 | 用途 |
isAnnotation() | 如果是注解类型则返回true |
isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定类型注解类型则返回true |
isAnonymousClass() | 如果是匿名类则返回true |
isArray() | 如果是一个数组类则返回true |
isEnum() | 如果是枚举类则返回true |
isInstance(Object obj) | 如果obj是该类的实例则返回true |
isInterface() | 如果是接口类则返回true |
isLocalClass() | 如果是局部类则返回true |
isMemberClass() | 如果是内部类则返回true |
5.1.2 Field类
方法 | 用途 |
equals(Object obj) | 属性与obj相等则返回true |
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj, Object value) | 设置obj中对应属性值 |
5.1.3 Method类
方法 | 用途 |
invoke(Object obj, Object… args) | 传递object对象及参数调用该对象对应的方法 |
5.1.4 Constructor类
方法 | 用途 |
newInstance(Object… initargs) | 根据传递的参数创建类的对象 |
6 SpringIOC中的反射
从存储着类信息的BeanDefinition中获得相关的构造方法,通过反射创建实例
SimpleInstantiationStrategy
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 如果不存在方法覆写,那就使用 java 反射进行实例化,否则使用 CGLIB,
// 方法覆写 请参见附录"方法注入"中对 lookup-method 和 replaced-method 的介绍
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 利用构造方法进行实例化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
// 存在方法覆写,利用 CGLIB 来完成实例化,需要依赖于 CGLIB 生成子类
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
BeanUtils
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));//使用构造方法的newInstance反射创建实例
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}