天天看點

Spring AOP與動态代理

AOP就是Spring面向切面程式設計,經常會在調用某一個方法前或者調用以後去執行其他的操作,這就需要用到AOP原理了
   AOP是怎麼做到切面點切入的呢,就是通過動态代理來實作的,動态代理目前主要有JDK的動态代理(InvocationHandler)和Cglib兩種
  首先,最早接觸到的代理應該是設計模式中的代理模式,是靜态代理,主要是有接口類,接口實作類和代理類,代碼如下
  ![在這裡插入圖檔描述](https://img-blog.csdnimg.cn/2019102110194620.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xoejEzNTEwOTcwNzQ1,size_16,color_FFFFFF,t_70)
           

代碼如下:

接口類

package test;

public interface Caculate {

public int add(int a,int b);
public int sub(int a,int b);
           

}

接口實作類

package test;

public class AddCaculate implements Caculate{

@Override
public int add(int a, int b) {
	// TODO Auto-generated method stub
	return a+b;
}

@Override
public int sub(int a, int b) {
	// TODO Auto-generated method stub
	return a-b;
}
           

}

代理類

package test;

public class CaculateProxy implements Caculate{

private Caculate caculate;

public CaculateProxy(Caculate caculate) {
	
	this.caculate=caculate;
	// TODO Auto-generated constructor stub
}

@Override
public int add(int a, int b) {
	// TODO Auto-generated method stub
	return caculate.add(a, b);
}

@Override
public int sub(int a, int b) {
	// TODO Auto-generated method stub
	return caculate.add(a, b);
}
           

}

測試

AddCaculate addCaculate = new AddCaculate();

CaculateProxy proxy = new CaculateProxy(addCaculate);

proxy.add(1, 2);

proxy.sub(2, 1);

這裡就是靜态代理類的實作,那麼問題來了,如果需要增添或者删除一些方法,那麼代理類也要跟随着做相應的修改,此時就需要動态代理來解決這個問題了,那麼動态代理是啥原理實作的呢,看下面一張圖

Spring AOP與動态代理

這是java代碼在jvm裡邊編譯解析程子節碼的過程,Java的源代碼.java檔案通過編譯器編譯成.class檔案後,jvm就在加載類的時候,會根據.class的組織結構,生成對應的位元組碼 再進行加載類,這就實作了.class在運作期間才被确定,就成就了動态代理了

1.InvocationHandler模式

InvocationHandler就是在靜态代理模式上引入了InvocationHandler類,這個類就是負責在運作時候,動态調用proxy所要調用的對應實作類的方法,代碼如下

接口類和實作類還是和靜态代理一樣

代理類如下,實作了InvocationHandler:

package test;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class CaculateProxy implements InvocationHandler{

private Object caculate;

public CaculateProxy(Object caculate) {
	
	this.caculate=caculate;
	// TODO Auto-generated constructor stub
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	// TODO Auto-generated method stub
	method.invoke(caculate, args);
	return null;
}
           

}

測試類

AddCaculate addCaculate = new AddCaculate();

InvocationHandler invocationHandler = new CaculateProxy(addCaculate);

Caculate caculate = (Caculate) Proxy.newProxyInstance(addCaculate.getClass().getClassLoader(),

addCaculate.getClass().getInterfaces(), invocationHandler);

caculate.add(2, 3);

caculate.sub(1, 2);

我們看到addCaculate.getClass(),這段代碼實際上我們是把實作類中的接口資訊與觸發器invocationHandler綁定,也就是說如果實作類有接口中沒有的方法是不能被代理的。總的來說,JDK這種代理1)要保證有接口,2)不能代理接口中沒有的方法

為避免上面的兩種缺陷,這就是要說的另一種動态代理實作方式,那就是代理類繼承被代理類,不需要接口,這種實作如 Cglib,Cglib是實作了MethodInterceptor攔截器

它的流程是這樣的:

1).查找A上的所有非final 的public類型的方法定義;

2).将這些方法的定義轉換成位元組碼;

3).将組成的位元組碼轉換成相應的代理的class對象;

4).實作 MethodInterceptor接口,用來處理 對代理類上所有方法的請求(這個接口和JDK動态代理InvocationHandler的功能和角色是一樣的

本文參考文章:http://blog.csdn.net/luanlouis/article/details/24589193