Java 設計模式
1 Java 反射技術
Java 反射技術應用廣泛,它能夠配置:類的全限定名、方法和參數,完成對象的初始化,甚至是反射某些方法。這樣大大增強Java的可配置性,Spring IoC 的基本原理也是如此,當然Spring IoC 的代碼要複雜得多。
Java的反射內容繁多,包括對象構建、反射方法、註解、參數、接口等。下面主要講解:對象構建(包括麼有參數的和有參數的構建方法)和方法的反射調用。在Java中,反射是通過包java.lang.reflect.*來實現的。
反射的優點:只要配置就可以生成對象,可以解除程序的耦合度,比較靈活。缺點:運行比較慢。但是大部分情況下爲了靈活度,降低程序的耦合度,我們還是會使用反射的,比如:Spring IoC 容器。
1.1 通過反射構建對象
通過反射生成帶有無參的構建方法:
public class ReflectServiceImpl {
public void sayHello(String name){
System.out.println("Hello " + name );
}
}
通過反射生成一個對象,然後將其返回:
public ReflectServiceImpl getInstance(){
ReflectServiceImpl object = null;
try {
// 通過反射生成一個對象,然後將其返回。
object = (ReflectServiceImpl)Class.forName("com.feike.reflect.ReflectServiceImpl")
.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex){
ex.printStackTrace();
}
return object;
}
通過反射生成帶有有參的構建方法:
public class ReflectServiceImpl2 {
private String name;
public ReflectServiceImpl2(String name ){
this.name = name;
}
public void sayHello(){
System.out.println("hello " + name);
}
public ReflectServiceImpl2 getInstance(){
ReflectServiceImpl2 object = null;
try {
object = (ReflectServiceImpl2)Class.forName("com.feike.reflect.ReflectServiceImpl2")
.getConstructor(String.class).newInstance("張三");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | NoSuchMethodException
| SecurityException | IllegalArgumentException
| InvocationTargetException ex){
ex.printStackTrace();
}
return object;
}
}
1.2 調用反射對象的方法:
private static void reflectMethod(){
ReflectServiceImpl target = getInstance();
try {
// 第一個參數是方法名稱,第二個參數是參數類型,是一個列表,多個參數可以繼續編寫多個類型。
Method method = ReflectServiceImpl.class.getMethod("sayHello", String.class);
method.invoke(target,"張三");
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException ex){
ex.printStackTrace();
}
}
2 動態代理模式和責任鏈模式
動態代理和責任鏈無論在Spring還是MyBatis中都有重要的應用。
動態代理的意義在於生成一個佔位(又稱代理對象),來代理真實對象,從而控制真實對象的訪問。
代理模式示意圖:
代理必須分爲兩個步驟:
- 代理對象和真實對象建立代理關係。
- 實現代理對象的代理邏輯方法。
在Java中有多種動態代理技術,比如:JDK、CGLIB、Javassist、ASM,其中最常用的動態代理技術有兩種:一種是JDK動態代理,這是JDK自帶的功能;另一種是CGLIB,這是第三方提供的一個技術。目前,Spring 常用JDK和CGLIB,而MyBatista還使用了Javassist,無論哪種代理,他們的理念是相似的。在JDK動態代理中我們必須使用接口,而CGLIB不需要。
2.1 JDK動態代理
定義接口:
public interface HelloWorld {
public void sayHelloWorld();
}
實現接口:
public class HelloWorldImpl implements HelloWorld {
@Override
public void sayHelloWorld() {
System.out.println("Hello World !");
}
}
動態代理綁定和代理邏輯實現:
在JDK動態代理中,要實現代理邏輯必須去實現java.lang.reflect.InvocationHandler接口,他裏面定義了一個invoke方法,並提供接口數組用於下掛代理對象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyExample implements InvocationHandler {
// 真實對象
private Object target = null;
/**
* @method bind
* @author Feike
* @version 1.0
* @description 建立代理對象和真實對象的代理關係,並返回代理對象。
* @param target 真實對象
* @return java.lang.Object 代理對象
* @date 2020/6/18 22:30
*/
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
* @method invoke
* @author Feike
* @version 1.0
* @description 代理方法邏輯
* @param proxy 代理對象
* @param method 當前調度方法
* @param args 當前方法參數
* @return 代理結果返回
* @exception Throwable 異常
* @date 2020/6/18 22:32
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("進入代理邏輯方法");
System.out.println("在調度真實對象之前的服務");
//相當於調用sayHelloWorld 方法
Object obj = method.invoke(target,args);
System.out.println("在調用真實對象之後的服務");
return obj;
}
}