Spring AOP(面向切面編程)使用了兩種技術(shù)實(shí)現(xiàn),一種是JDK自帶的動(dòng)態(tài)代理,另外一種是使用cglib字節(jié)碼技術(shù)動(dòng)態(tài)生成代理類迟隅。Spring是如何選擇的了:
- 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,默認(rèn)情況先回選擇使用JDK代理技術(shù)實(shí)現(xiàn)AOP,但是也可以強(qiáng)制使用cglib實(shí)現(xiàn)動(dòng)態(tài)代理
- 如果目標(biāo)對(duì)象沒有實(shí)現(xiàn)接口,則會(huì)采用cglib技術(shù)實(shí)現(xiàn)AOP
cglib創(chuàng)建某個(gè)動(dòng)態(tài)代理類的模式是:
- 查找目標(biāo)類上所有非 final 的public類型的方法,將這些方法的定義轉(zhuǎn)換成字節(jié)碼
- 將組成的字節(jié)碼轉(zhuǎn)換成相應(yīng)的代理的class對(duì)象
- 代理類實(shí)現(xiàn)MethodInterceptor接口,用來處理代理類上所有方法的請(qǐng)求(中介)
下面是代碼:
定義一個(gè)通用接口,里面定義一些要攔截的方法
package com.minglangx.cglib;
/**
*
* @ClassName: UserService
* @Description: 通用接口類
* @author minglangx
* @date 2017年8月19日 下午12:02:34
*
*/
public interface UserService {
String getName(String name);
Integer getAge(int age);
}
定義一個(gè)目標(biāo)對(duì)象,實(shí)現(xiàn)這個(gè)通用接口
package com.minglangx.cglib;
/**
*
* @ClassName: UserServiceImpl
* @Description: 目標(biāo)對(duì)象
* @author minglangx
* @date 2017年8月19日 下午12:02:52
*
*/
public class UserServiceImpl implements UserService {
@Override
public String getName(String name) {
System.out.println("===getName===");
return name;
}
@Override
public Integer getAge(int age) {
System.out.println("====getAge=====");
return age;
}
}
核心代理類,實(shí)現(xiàn)MethodInterceptor接口
package com.minglangx.cglib;
import java.lang.reflect.Method;
import java.util.Arrays;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
*
* @ClassName: CglibDemo
*
* @Description: 代理類使用 Cglib實(shí)現(xiàn)動(dòng)態(tài)代理
*
* @author minglangx
*
* @date 2017年8月18日 下午12:33:51
*
*
*
*
*
*/
class CglibDemo implements MethodInterceptor {
/**
* Object obj 被代理的對(duì)象
* Method method 被攔截的方法
* Object[] objs 方法的參數(shù)
* MethodProxy methodProxy cglib中的代理對(duì)象
*
*
*/
@Override
public Object intercept(Object obj, Method method, Object[] objs, MethodProxy methodProxy) throws Throwable {
System.out.println("======before " + methodProxy.getSuperName() + "======");
System.out.println("被攔截的方法名稱-----" + method.getName());
System.out.println("被攔截的方法參數(shù)-----" + Arrays.asList(objs));
//invokeSuper(obj,objs) 第一個(gè)參數(shù)是被代理對(duì)象,第二個(gè)參數(shù)是參數(shù)集合
Object objNew = methodProxy.invokeSuper(obj, objs);
System.out.println("+++++before " + methodProxy.getSuperName() + "=====");
return objNew;
}
}
測(cè)試類
- 使用 Enhancer().setSuperclass(目標(biāo)對(duì)象); 設(shè)置要代理的對(duì)象
- 使用 Enchancer.setCallback(目標(biāo)對(duì)象); 將要代理對(duì)象的所有方法都轉(zhuǎn)發(fā)到intercept()方法上進(jìn)行攔截
- 使用Enchancer.create();獲取被代理的對(duì)象
package com.minglangx.cglib;
import net.sf.cglib.proxy.Enhancer;
import com.minglangx.cglib.UserService;
import com.minglangx.cglib.UserServiceImpl;
public class MainDemo {
public static void main(String[] args) {
CglibDemo cglibDemo = new CglibDemo();
//cglib中的加強(qiáng)器,用來創(chuàng)建動(dòng)態(tài)代理
Enhancer enhancer = new Enhancer();
//設(shè)置要?jiǎng)討B(tài)創(chuàng)建的類
enhancer.setSuperclass(UserServiceImpl.class);
/*
* 設(shè)置回調(diào).這里相當(dāng)于是對(duì)于代理類上所有方法的回調(diào),都會(huì)調(diào)用CallBack循诉,
* 而Callback需要執(zhí)行intercept()方法進(jìn)行攔截
*/
enhancer.setCallback(cglibDemo);
//得到實(shí)際對(duì)象的接口類型,調(diào)用其方法
UserService o =(UserService) enhancer.create();
o.getName("zhangs");
o.getAge(25);
}
}
輸出結(jié)果: 我們看到在被代理對(duì)象調(diào)用方法之前成功實(shí)現(xiàn)了方法的攔截
image.png