1. 程式人生 > >Java動態代理+註解體現Spring AOP思想

Java動態代理+註解體現Spring AOP思想

在MVC的架構中,優秀的程式碼是Service業務層只做業務邏輯處理,如果要新增新功能(如日誌,事務等),不應該汙染業務層程式碼。
講得很抽象,簡單來說,如果我要在業務層新增日誌功能,在業務層程式碼內不應該出現Logger這個東西。
想知道怎麼實現嗎?使用JAVA的動態代理技術,這裡體現了Spring AOP切面程式設計的思想。

1. 什麼是動態代理?

查理論能查幾頁紙,這裡簡單總結一句話:呼叫Proxy返回一個代理物件,使用這個代理物件執行你的方法時,它會先執行代理物件裡的方法再執行你的業務方法。
這像什麼?就是Spring AOP切面程式設計。

2. 為什麼要用動態代理?

業務層程式碼專注業務處理,新增新功能時,如日誌,事務等。不汙染業務程式碼。

3. 怎麼用?

這裡給出一個例子:
業務場景:使用者業務處理介面(UserService)內有個addUser(String name)方法,我現在需要給他加上日誌輸出。但是要求不能在該方法內寫Logger的程式碼。(不汙染業務程式碼)。

3.1 首先我們建一個自定義註解類: Log.java

package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定義日誌註解,用於判斷該方法執行前是否需要寫入日誌 * @author GANAB * */ @Retention(RetentionPolicy.RUNTIME) @Target(value=ElementType.METHOD) public @interface Log {}

3.2 建一個代理類LogProxy.java

package proxy;

import java.lang.reflect.InvocationHandler;
import
java.lang.reflect.Method; import java.lang.reflect.Proxy; import annotation.Log; public class LogProxy implements InvocationHandler{ //宣告被代理類物件 private Object src; //在私有的構造中給成員設定值 private LogProxy(Object src){ this.src=src; } /** * 提供一個靜態的方法返回代理物件 */ public static Object factory(Object src){ Object proxyedObj = //生成被代理類的介面的子類 Proxy.newProxyInstance( LogProxy.class.getClassLoader(), src.getClass().getInterfaces(), new LogProxy(src)); return proxyedObj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果該方法帶有Log註解,先執行Logger操作再執行該方法 if(method.isAnnotationPresent(Log.class)){ System.out.println("logger..."); return method.invoke(src, args); }else{ return method.invoke(src, args); } } }

3.3 UserService介面新增日誌功能的方法上加上註解@Log

public interface UserService {
    @Log
    int addUser(String name);
}

public class UserServiceImpl implements UserService{

    @Override
    public int addUser(String name) {
        System.out.println("add user "+ name);
        return 1;
    }
}

3.4 最後進行測試

public class ProxyTest {

    public static void main(String[] args) {
        //特點: 最先執行最後返回的代理物件的代理方法。如下:先執行Log最後執行業務方法。
        UserService service = new UserServiceImpl();
        service = (UserService)LogProxy.factory(service);
        service.addUser("abel");
    }
}

輸出結果為:

logger...
add user abel

4. 總結

使用動態代理可以使業務程式碼只專注業務邏輯處理。新增功能可以採用這種方法新增。