Spring AOP之代理設定模式
阿新 • • 發佈:2018-12-14
一.什麼是AOP
Spring的AOP:即面向切面程式設計,其程式碼實質,即代理模式的應用。
二.三種代理設定模式(目標物件不願意做的事,代理物件給我們實現)
代理模式程式碼的主要特點是:不改變原有類的前提下,在原有類某些方法執行前後,插入任意程式碼。所以代理模式需要寫新的類對原有的類進行包裝。代理模式目前實現的方式有三種: 這裡先定義一個介面
package com.offcn.test;
public interface Singer {
public void singing();
public void dancing();
}
在定義一個實現類
package com. offcn.test;
/**
* 目標物件
*/
public class WangBaoQiang implements Singer{
@Override
public void singing() {
System.out.println("正在唱歌");
}
@Override
public void dancing() {
System.out.println("正在跳舞");
}
}
- 靜態代理:需要增強原有類的哪個方法,就需要對在代理類中包裝哪個方法。個人理解,從功能上來說,原有類和代理類不一定要實現共同介面,但是為了賦予代理和和被代理類之間的邏輯關係,增加程式的可讀性,可理解性,邏輯性,增加代理物件和被代理物件之間的關係,以更加符合面向物件程式設計是思維,而應該實現共同介面。
//首先例項化的物件是王寶強,就是目標物件
Singer singer = new WangBaoQiang();
//例項化代理物件來呼叫其方法(在呼叫目標物件的前後做一些相關的操作)
ProxyWang proxyWang = new ProxyWang(singer);
proxyWang.singing();
//缺點: 擴充套件性差,每次只要有不同的目標物件,即使操作一樣,也要重新生成一個代理物件
//優點: 好理解,程式碼看起來不復雜
- .動態代理(最常用):使用反射機制,方法和物件都是傳入的變數,就可以經過傳入的物件和方法而動態呼叫被代理物件的任何方法,jdk中提供了實現此動態代理的api(Proxy),被代理類必須實現介面
package com.offcn.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 實現動態代理
*/
public class ProxyAi implements InvocationHandler {
private Object object;
public ProxyAi(Object object) {
this.object = object;
}
//只要你的通過呼叫目標物件的方法都會走這個方法
//第一個引數是代理物件,第二個引數是你呼叫目標物件的方法(通過反射來實現),第三個引數是你呼叫目標物件的方法裡的引數
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通過反射來呼叫目標物件的方法,第一個引數你要呼叫目標物件方法的類,第二個引數是你要呼叫目標物件方法的引數
Object o = null;
if (method.getName().equals("singing")){
System.out.println("試唱成功");
o = method.invoke(object,args);
System.out.println("唱歌結束");
}else if (method.getName().equals("dancing")) {
System.out.println("搭建舞臺成功");
o = method.invoke(object, args);
System.out.println("演出結束");
}
return o;
}
}
Singer singer = new WangBaoQiang();
//jdk提供了一個代理類Proxy 第一個引數是類載入器,第二個引數是目標物件的class,第三個引數是代理物件
//返回值型別是Object
Singer singer1 = (Singer) Proxy.newProxyInstance(
singer.getClass().getClassLoader(), new Class[]{Singer.class}, new ProxyAi(singer));
singer1.singing();
- Cglib代理:返回物件是代理物件的子類,不需要代理物件實現介面。當呼叫原物件方法時,實際上呼叫的是代理子類的方法。
引入jar包
package com.offcn.test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//MethodInterceptor 方法攔截器
public class CglibProxy implements MethodInterceptor {
//例項化物件
private Object object;
//這個方法就是為了建立代理物件
public Object getCglibProxy(Object object){
this.object=object;
//得到建立代理物件的物件
Enhancer enhancer = new Enhancer();
//設定類載入器
enhancer.setClassLoader(this.object.getClass().getClassLoader());
//設定父類
enhancer.setSuperclass(this.object.getClass());
//設定回撥 ,只要走下面這個方法都要走回調
enhancer.setCallback(this);
// 建立代理物件
return enhancer.create();
}
//這個方法就是在呼叫目標物件的方法都會執行這個方法
//第一個引數是代理物件,第二個引數是目標物件的方法,第三個引數是目標物件的方法引數,第四個引數是代理物件攔截方法的物件
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("舞臺搭建成功");
Object ob = method.invoke(object, objects);
return ob;
}
}
//例項化一個cglibProxy代理物件類
CglibProxy cglibProxy = new CglibProxy();
Singer singer = new WangBaoQiang();
Singer singer1 = (Singer) cglibProxy.getCglibProxy(singer);
singer1.singing();