Java動態代理+註解體現Spring AOP思想
阿新 • • 發佈:2019-01-08
在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. 總結
使用動態代理可以使業務程式碼只專注業務邏輯處理。新增功能可以採用這種方法新增。