JDK動态代理
核心思想:通過實作被代理類的所有接口,生成一個位元組碼檔案後構造一個代理對象,通過持有反射構造被代理類的一個執行個體,再通過invoke反射調用被代理類執行個體的方法,來實作代理。
缺點:JDK動态代理的對象必須實作一個或多個接口

流程圖
知識點
- JDK實作動态代理需要實作類通過接口定義業務方法
- JDK生成的代理類以”$Proxy”為開頭進行命名
- JDK代理生成的代理類的Method在static靜态代碼塊中進行初始化;
- public接口生成的代理類package為”com.sun.proxy”;
- JDK動态代理需要實作InvocationHandler接口;
代碼:
package com.quancheng;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
Student stu = new Student();
CusInvocationHandler handler = new CusInvocationHandler(stu);
Play instance = (Play) Proxy.newProxyInstance(stu.getClass().getClassLoader(), stu.getClass().getInterfaces(), handler);
instance.play();
}
}
class CusInvocationHandler implements InvocationHandler {
private Object target;
public CusInvocationHandler(Object object) {
this.target = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.err.println("代理方法處理");
return method.invoke(target, args);
}
}
interface Play {
void play();
}
class Student implements Play {
@Override
public void play() {
System.err.println("student ====>");
}
}
生成的代理類示例:
import dynamic.proxy.UserService;
import java.lang.reflect.*;
public final class $Proxy11 extends Proxy
implements UserService
{
// 構造方法,參數就是剛才傳過來的MyInvocationHandler類的執行個體
public $Proxy11(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
// 省略
}
/**
* 被代理的方法
*/
public final void add()
{
try
{
// 實際上就是調用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二個問題就解決了
super.h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
// 省略
}
public final String toString()
{
// 省略
}
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
// 在靜态代碼塊中擷取了4個方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
cglib動态代理
核心思想:CGLib采用了非常底層的位元組碼技術,其原理是通過位元組碼技術為一個類建立子類(CGLib底層是通過繼承實作的動态代理),并在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。JDK動态代理與CGLib動态代理均是實作Spring AOP的基礎;底層:使用一個小而快的位元組碼處理架構ASM(Java位元組碼操控架構),來轉換位元組碼并生成新的類
缺點:不能代理final修飾的類
示例代碼:
//被代理的類即目标對象
public class A {
public void execute(){
System.out.println("執行A的execute方法...");
}
}
//代理類
public class CGLibProxy implements MethodInterceptor {
/**
* 被代理的目标類
*/
private A target;
public CGLibProxy(A target) {
super();
this.target = target;
}
/**
* 建立代理對象
* @return
*/
public A createProxy(){
// 使用CGLIB生成代理:
// 1.聲明增強類執行個體,用于生産代理類
Enhancer enhancer = new Enhancer();
// 2.設定被代理類位元組碼,CGLIB根據位元組碼生成被代理類的子類
enhancer.setSuperclass(target.getClass());
// 3.//設定回調函數,即一個方法攔截
enhancer.setCallback(this);
// 4.建立代理:
return (A) enhancer.create();
}
/**
* 回調函數
* @param proxy 代理對象
* @param method 委托類方法
* @param args 方法參數
* @param methodProxy 每個被代理的方法都對應一個MethodProxy對象,
* methodProxy.invokeSuper方法最終調用委托類(目标類)的原始方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//過濾不需要該業務的方法
if("execute".equals(method.getName())) {
//調用前驗證權限(動态添加其他要執行業務)
AuthCheck.authCheck();
//調用目标對象的方法(執行A對象即被代理對象的execute方法)
Object result = methodProxy.invokeSuper(proxy, args);
//記錄日志資料(動态添加其他要執行業務)
Report.recordLog();
return result;
}else if("delete".equals(method.getName())){
//.....
return methodProxy.invokeSuper(proxy, args);
}
//如果不需要增強直接執行原方法
return methodProxy.invokeSuper(proxy, args);
}
}