java提供的動態代理機制是一種強大的語言結構,可以爲一個或多個接口創建代理對象而不需要預先擁有一個接口的實現類。Spring的AOP也是建立在java的代理機制之上的,本篇文章通過一個例子簡單理解一下java的動態代理機制實現AOP。
本例將通過動態代理來實現日誌輸出功能:
1、編輯Login接口,提供login()方法用於執行管理員登錄操作。
public interface Login {
public void login();
}
2、編輯Login接口的實現類LoginImpl,此類只包含業務邏輯代碼,模擬管理員的登錄操作。
public class LoginImpl implements Login {
@Override
public void login() {
System.out.println("===========登錄==========");
}
}
3、編輯LogProxy,此類實現Java提供的InvocationHandler接口,通過這個代理類,可以在運行時自動創建指定接口的代理對象,並由此對象完成相關業務邏輯流程。
public class LogProxy implements InvocationHandler {
private Object proxyObj;
public LogProxy(Object proxyObj) {
this.proxyObj = proxyObj;
}
//創建代理對象
public static Object bind(Object object) {
Class cls = object.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new LogProxy(object));
}
//在唯一的切入點的前後執行日誌輸出
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
login(method);
Object object = method.invoke(proxyObj, args);
logout(method);
return object;
}
//橫向關注點,實現輸出日誌功能
private void logging(String msg) {
System.out.println(msg);
}
private void login(Method method) {
logging("方法" + method.getName() + "執行之前的日誌信息");
}
private void logout(Method method) {
logging("方法" + method.getName() + "執行之前的日誌信息");
}
}
4、測試類
public class TestLog {
public static void main(String[] args) {
Login login = (Login) LogProxy.bind(new LoginImpl());
login.login();
}
}
5、輸出
方法login執行之前的日誌信息
===========登錄啦==========
方法login執行之前的日誌信息
使用面向接口編程和動態代理機制,有效地實現各功能模塊之間解耦,用於實現日誌記錄功能的代碼和實現業務邏輯的代碼不再相互依賴,只有調用業務邏輯並且記錄日誌時,二者才產生關聯。同時,任何業務邏輯需要加入日誌輸出功能,只需要通過代理工廠創建一個代理對象即可。