關於AOP和代理的一點想法

    AOP從本質上講是在咱們可視以外改變了程序的運行軌跡,比方說,有個方法method執行完,就結束了,經過AOP在method前插入N個操做、在method後插入N個操做,那麼這時要執行method方法,須要執行前面的N個操做才能進入,要退出,還得把後面的N個操做走完。java

    AOP適合須要織入共性操做的場景,如:全部模塊都須要事務控制,那麼就經過AOP的方式把事務控制的邏輯織入到每一個模塊的方法裏。AOP有三種織入操做,即前置加強、後置加強、環繞加強,環繞加強不一樣於前置後置,它能夠決定是否執行被代理方法,改變目標方法的返回值。git

    談到織入額外操做,不得不談代理模式。代理者再代理被代理者時,能夠作其餘額外操做,例如:祕書是老闆的代理,公司要求客戶必須先和祕書通電話確認有預定才能和老闆通電話。ide

代碼以下:工具

public interface Phone {
	public void listen();
}


public class Boss implements Phone {

	@Override
	public void listen() {
		System.out.println("我是老闆");
	}

}

public class Secretary implements Phone {
	private Boss boss;

	public Secretary() {
	}

	public Secretary(Boss boss) {
		this.boss = boss;
	}

	@Override
	public void listen() {
		System.out.println("已經預定");
		boss.listen();
	}

}

    代理模式包括三種角色:this

    一、抽象主題:定義被代理者和代理者共用的接口,也就是上例的Phone接口;.net

    二、實際主題:實現抽象主題接口的類,就是上例的Boss類設計

    三、代理(Proxy):也實現了抽象主題接口,也存放了實際主題的引用,能夠控制對被代理對象的訪問。代理

    用代理模式能夠織入一些額外操做,如上例的老闆接電話前,是經過祕書確認是否預定過的,但是這種模式是靜態的,每一個被代理類都要寫一個代理類,很是麻煩。接下來看怎麼解決這個問題。code

    JDK提供一種動態代理的機制,動態代理本質上是在運行期動態生成代理的java字節碼,這樣就能夠代理多個類了,那麼咱們看用動態代理怎麼代理Boss這個打電話操做,對象

    一、經過實現InvocationHandler接口來自定義本身的InvocationHandler;

    二、Proxy.newProxyInstance來獲取代理類

public class JDKDynamicProxyTest {

	public static void main(String[] args) {
		Boss boss = new Boss();
		InvocationHandler invocationHandler = new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("已經預定");
				Object result = method.invoke(boss, args);
				return result;
			}
		};
		Phone proxy = (Phone) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
				boss.getClass().getInterfaces(), invocationHandler);//獲取代理對象
		proxy.listen();
	}
}

    這樣子作的好處顯而易見,對於共性業務能夠定義一個InvocationHandler,用Proxy.newProxyInstance獲取每一個類的代理對象,是否是很省事呢?這裏全靠動態生成Java字節碼,只有是怎麼動態生成的,這裏就不討論了。

    這樣又會有新的問題,JDK自帶動態代理只能代理有實現了接口的類,那麼沒有接口的類怎麼被代理呢?這讓我把目光轉向了ASM和Cglib,ASM是一個字節碼生成工具,須要對JVM內部結構包括class文件的格式和指令集都很熟悉,開發效率比較低、難度比較大。Cglib底層雖然依賴於ASM,可是作了不少封裝,使用方便,因爲cglib生成的代理類是繼承與被代理類的,全部被代理類中若是有final方法,是不能被代理的。接下來看看怎麼經過cglib來代理老闆接電話。

    定義了一個MethodInterceptor,用來攔截被代理類中要執行的方法。

public class CglibProxyTest {
	public static void main(String[] args) {
		Phone proxy = (Phone) Enhancer.create(Boss.class, new MethodInterceptor() {
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
				System.out.println("已經預定");
				return proxy.invokeSuper(obj, args);
			}
		});
		proxy.listen();
	}
}

    自此,咱們解決了大部分問題,能夠用cglib來實現AOP了,但是cglib不能嵌套代理,也就是被代理的類,不能再次被cglib代理,當要往一個類中織入多個操做邏輯時,又該怎麼實現呢?

    這些問題將在《TeaFramework——AOP的設計與實現》中講到。

     項目地址:https://git.oschina.net/lxkm/teaframework
     博客:https://my.oschina.net/u/1778239/blog 

相關文章
相關標籤/搜索