Spring IOC——Java反射

1 基础

spring的技术核心之一是动态代理,而动态代理的核心是java反射。所以如果要学习spring框架,java反射是我们永远也绕不开的一个坎,这是基础。

2 反射定义

反射被视为动态语言的关键,java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法

对于任意一个对象,都能够调用它的任意方法和属性

这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

3 反射概述

Class类java.lang.reflect类库一起对反射的概念进行了支持,该类库中包含了FieldMethodConstructor类(每个类都实现了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();
    }
}

java springbean 反射 invoke spring ioc 反射_构造方法

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();
    }
}

java springbean 反射 invoke spring ioc 反射_ide_02

反射私有方法(私有成员变量也大同小异)

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();
    }
}

错误演示

java springbean 反射 invoke spring ioc 反射_ide_03

正确演示

java springbean 反射 invoke spring ioc 反射_spring_04

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());
		}
	}