一、靜態代理
可以用現實生活中的例子來說,房東有房子要出售,但是不可能一下子就找到客戶,此時可以交給代理去做,那麼代理就會和房東一樣具有租房的權利,但是代理就不一定只會去租房,還會收取中介費等,而客戶最後也可以通過代理實現租房。
放到程序中,可以認爲是代理實現的不僅僅是幫房東租房的業務,還可以實現其他的功能,這樣就可以擴充具體實現類的功能!!
通過上圖,可以得到四個角色:客戶、代理角色、真實角色、抽象接口
接口:租房
public interface Rent {
public void rent();
}
房東 : 真實的角色
public class Host implements Rent{
public void rent() {
System.out.println("房東出租房子");
}
}
代理角色:中介
//中介代理 幫房東租房
public class Agent implements Rent {
//拿房東
private Host host;
public Agent(Host host){
this.host=host;
}
public void rent() {
look();
host.rent();
fee();
}
public void look(){
System.out.println("帶客戶看房");
}
public void fee(){
System.out.println("收取中介費");
}
}
client:客戶
public class Client {
public static void main(String[] args) {
Agent agent = new Agent(new Host());
agent.rent();
}
}
二、動態代理
- 動態代理和靜態代理角色一樣,動態代理是直接生成的,不是直接寫的。
Spring AOP中的動態代理主要有兩種方式:JDK動態代理和CGLIB動態代理
JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。現在都推薦面向接口編程,我們做的項目都是各種接口+實現類,所以是不是覺得這種代理方式和現在的接口編程很符合呢!
下面我們延續上面的例子進行說明,上面的靜態代理對象是我們寫出來的,而動態代理可以生成!!
完整代碼
房東 真實的角色
public class Host implements Rent{
public void rent() {
System.out.println("房東出租房子");
}
}
Rent 接口
public interface Rent {
public void rent();
}
自動生成代理類
package com.zhoudan.demo2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//可以自動生成代理類
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理類
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
//處理代理實例 返回結果 可以理解爲得到調用方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(rent, args);
fee();
return result;
}
public void seeHouse(){
System.out.println("中介帶着看房子");
}
public void fee(){
System.out.println("中介收取中介費");
}
}
client
public class Client {
public static void main(String[] args) {
//真實角色
Host host = new Host();
//代理角色沒有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//處理接口對象
pih.setRent(host);
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
三、AOP
與AspectJ的靜態代理不同,Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時爲方法生成一個AOP對象(我們可以把它稱之爲‘代理對象’),這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法。
-
橫切關注點:跨越應用程序多個模塊的方法或功能。即是,與我們業務邏輯無關的,但是我們需要關注的部分,就是橫切關注點。如日誌 , 安全 , 緩存 , 事務等等 …
-
切面(ASPECT):橫切關注點 被模塊化 的特殊對象。即,它是一個類。
-
通知(Advice):切面必須要完成的工作。即,它是類中的一個方法。
-
目標(Target):被通知對象。
-
代理(Proxy):向目標對象應用通知之後創建的對象。
-
切入點(PointCut):切面通知 執行的 “地點”的定義。
-
連接點(JointPoint):與切入點匹配的執行點。
使用aop時要先導入依賴和在xml中進行相應的配置和約束:
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
定義一個接口和一個實現類:
有以下三種實現方式:
方式一:
先定義兩個類,分別執行前置通知和後置通知
方式二:使用自定義的類作爲切入面
方式三:使用註解
由於筆者能力有限,對aop的理解還不夠透徹。如果有錯誤的地方,大家可以多多指出,我們共同進步!!