一、反射
1.1 反射機制概述
反射機制是建立在類對象(Class對象)上的。所有的類都存在一個類對象,這個類對象用域提供類本身的信息,比如有幾種構造方法,有多少屬性,有哪些普通方法······
1.2 反射機制作用
-
Spring的一個核心就是控制反轉(Inversion of Control,IoC),其基本原理就是反射機制。如何管理bean,如何由全限定名創建對象······
-
使用反射機制的一個重要目的就是要抵達程度的增強Java的可配置性和可擴展性。
-
使用反射還可以用來破壞單例模式。
package bean; public class Girlfriend { public static final Girlfriend INSTANCE = new Girlfriend("她", 18); private String name; private Integer age; private Girlfriend(String name, Integer age) { this.name = name; this.age = age; } }
public class GirlfriendFactory { public static Girlfriend getGirlfriend(String name, Integer age) { Girlfriend girl = null; try { // 獲取Girlfriend類的 Class對象 Class<?> cls = Class.forName("bean.Girlfriend"); // 獲取其申明的全部構造方法(包括private的和public的) Constructor<?> constructor = cls.getDeclaredConstructor(String.class, Integer.class); constructor.setAccessible(true); // 調用構造方法創建對象 girl = (Girlfriend) constructor.newInstance(name, age); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { e.printStackTrace(); } return girl; } }
二、註解
2.1 JDK自帶註解
-
@Override
聲明重寫父類方法的註解。
要求編譯器幫我們檢查是否成功的覆蓋,如果沒有父類方法,編譯器將會進行報錯提示 。 -
@Deprecated
聲明方法過時了,不在建議使用。
要求編譯器在編譯的過程中對於這樣的方法發出警告,提示方法過時 。 -
@SuppressWarnings()
壓制警告。
提示編譯器,在編譯的過程中對指定類型的警告不再提示 。常用的參數有
unchecked
、unused
、all
等。 -
@FunctionalInterface
約定函數式接口。
在編譯時檢查接口是否爲函數式接口(有且只有一個抽象方法的接口) 。
2.2 四個元註解
元註解用於構成自定義註解。而自定義註解的機會並不是很多,只列舉了一些最最最常用的參數。
-
@Target
描述註解的使用範圍(即:被修飾的註解可以用在什麼地方) 。
常用參數有
ElementType.TYPE
、ElementType.FILED
、ElementType.METHOD
、ElementType.PARAMETER
等。 -
@Retention
描述註解保留的時間範圍(即:被描述的註解在它所修飾的類中可以被保留到何時) 。
常用參數有
RetentionPolicy.RUNTIME
等。 -
@Documented
描述在使用 javadoc 工具爲類生成幫助文檔時是否要保留其註解信息 。
-
@Inherited
使被它修飾的註解具有繼承性(如果某個類使用了被@Inherited修飾的註解,則其子類將自動具有該註解) 。
2.3 自定義註解
2.3.1 定義
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Name {
String value();
}
2.3.2 使用
package bean;
public class Girlfriend {
@Name(value = "她")
private String name;
@Age
private Integer age;
}
2.3.3 解析
public class GirlfriendFactory {
public static Girlfriend getGirlfriend() {
Girlfriend girl = null;
try {
// 獲取Class對象
Class<?> cls = Class.forName("bean.Girlfriend");
// 獲取默認public無參構造器
Constructor<?> constructor = cls.getDeclaredConstructor();
// 創建對象
girl = (Girlfriend) constructor.newInstance();
// 遍歷所有申明的字段(包括private和public的)
for (Field field : cls.getDeclaredFields()) {
field.setAccessible(true);
// 如果註解修飾則給該字段注入相應的值
if (field.isAnnotationPresent(Name.class)) {
Name annotation = field.getAnnotation(Name.class);
field.set(girl, annotation.value());
} else if (field.isAnnotationPresent(Age.class)) {
Age annotation = field.getAnnotation(Age.class);
field.set(girl, annotation.value());
}
}
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
return girl;
}
}
三、控制反轉
控制反轉(Inversion of Control,IoC)是一種設計原則/設計思想,可以用來降低代碼之間的耦合度。
IoC的實現方式有依賴注入(Dependency Injection,DI)和依賴查找(Dependency Lookup,DL)兩種。而Spring中的IoC使用的是DI。
IoC可以認爲是一種全新的設計模式,但是理論和時間成熟相對較晚,並沒有包含在GoF中。
3.1 依賴注入
依賴注入是指自身對象中的內置對象是通過注入的方式創建的。依賴注入有兩種實現方式:setter注入和構造器注入。IoC容器全權負責組件的裝配,它會把符合依賴關係的對象通過屬性(bean的setter方法)或者是構造器傳遞給需要的對象。相對於IoC而言,DI更加準確大的描述了IoC的設計理念。
所謂依賴注入, 即對象之間的依賴關係由容器在應用系統運行期來決定。也就是由容器動態地將某種依賴關係的目標對象實例注入到應用系統中的各個關聯的對象之中 。
3.2 IoC和DI的區別和聯繫
- IoC是設計思想/設計原則;而DI是IoC的實現方式。
- DI是後來別的大佬總結出來的能夠更加精確描述IoC理念的實現方式。
- 在Spring中IoC基本上等價於DI。
四、面向切面編程
面向切面編程(Aspect Oriented Programming,AOP)的是依靠動態代理模式去實現的。(當然也不僅僅限於動態代理)。所謂的代理就是通過代理對象去調用真實對象,調用代理方法會同時攔截真實方法,並可以加一些別的邏輯。
通常情況下:
- 真實對象的方法通常是核心業務邏輯(如增刪改查)——可以稱爲切點。
- 代理對象加入的是周邊功能邏輯(如記錄日誌)——可以抽取封裝爲切面。
- 這樣代理的過程也就是將切點和切面編制在一起的過程。
五、Spring的主要設計模式
一個優秀成熟的Java框架,必然離不開反射和代理。
推薦博客 Spring框架中的設計模式(二)