參照MOOC<java核心技術高階>,使用java動態代理來實現一個簡單的AOP
AOP vs. OOP
OOP
面向對象編程,將功能需求劃分爲獨立的、不同的、功能完善的類,通過繼承、多態等方式實現相同或者不同的行爲
AOP
面向切面編程,將通用的需求功能從衆多類中提取出來,使得衆多類共享一個行爲。
關係
AOP是OOP的補充
OOP的不足之一關鍵業務和非關鍵業務的耦合。
如僱員類Employee,核心業務是work,非核心的業務(高可變性)是記錄(record) work前
後的狀態信息,比如開始時間、使用的工具等,隨着需求可能不斷變化。
如果只使用OOP,那麼要把非關鍵業務代碼record寫入類中,一方面是耦合性高,另一方面是這種
高可變性的業務可能造成修改頻繁,難以維護。
如何將非關鍵業務從耦合中分離出來,統一管理,便於修改? --AOP
怎麼實現AOP?
java動態代理的特性很適合AOP。
動態代理會攔截特定的方法調用,進行加工(添加非關鍵的業務),在調用真正的業務方法。
利用動態代理實現一個SimpleAOP
場景描述:
有Person類,關鍵業務是eat,非關鍵業務是在eat之前洗手(wash hands),
eat之後擦嘴(wipe mouth)
具體步驟:
1- 創建Person接口
public interface Person {
void eat();
String getName();
}
2- 實現Person
public class PersonImpl implements Person {
private String name;
public PersonImpl(String name){
this.name =name;
}
@Override
public void eat(){
System.out.println(name+" is eating!");
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3- 創建調用處理器(實現InvocationHandler)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonProxyHandler implements InvocationHandler {
private Person person;//持有真正被調用的對象
public PersonProxyHandler(Person p){
this.person=p;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//before eat
System.out.println(person.getName()+" is washing hands!");
//eat
Object res = method.invoke(person,args);
//after eat
System.out.println(person.getName()+" is wiping mouth!");
return res;
}
}
4- 生成動態代理並調用方法
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
//創建目標對象
PersonImpl edwinxu = new PersonImpl("Edwin0");
//創建調用處理器對象
PersonProxyHandler pph = new PersonProxyHandler(edwinxu);
//動態生成代理對象
Person personProxy = (Person) Proxy.newProxyInstance(
PersonImpl.class.getClassLoader(),PersonImpl.class.getInterfaces(),pph
);
while (true){
try {
personProxy.eat();//執行關鍵業務代碼
edwinxu.setName("Edwin"+(int)(Math.random()*10));
Thread.sleep(3000);
System.out.println();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
特殊說明:
要模仿AOP,按道理理應使用配置文件形式,但是這裏簡化了。
輸出:
Edwin0 is washing hands!
Edwin0 is eating!
Edwin0 is wiping mouth!
Edwin5 is washing hands!
Edwin5 is eating!
Edwin5 is wiping mouth!
可見通過動態代理,在關鍵業務(eat)上添加了一些其他的高可變的非關鍵業務。