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