java實現動態代理的方式有幾種?

AOP的攔截功能是由java中的動態代理來實現的。說白了,就是在目標類的基礎上增長切面邏輯,生成加強的目標類(該切面邏輯或者在目標類函數執行以前,或者目標類函數執行以後,或者在目標類函數拋出異常時候執行。不一樣的切入時機對應不一樣的Interceptor的種類,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。java

 

那麼動態代理是如何實現將切面邏輯(advise)織入到目標類方法中去的呢?下面咱們就來詳細介紹並實現AOP中用到的兩種動態代理。緩存

AOP的源碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理底層則是藉助asm來實現的。總的來講,反射機制在生成類的過程當中比較高效,而asm在生成類以後的相關執行過程當中比較高效(能夠經過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的接口。若是沒有上述前提,jdk動態代理不能應用。由此能夠看出,jdk動態代理有必定的侷限性,cglib這種第三方類庫實現的動態代理應用更加普遍,且在效率上更有優點。框架

1.定義接口和實現類ide

package com.meituan.hyt.test3.service;  
  
  
public interface UserService {  
    public String getName(int id);  
  
    public Integer getAge(int id);  
}
package com.meituan.hyt.test3.service.impl;  
  
import com.meituan.hyt.test3.service.UserService;  
  
  
public class UserServiceImpl implements UserService {  
    @Override  
    public String getName(int id) {  
        System.out.println("------getName------");  
        return "Tom";  
    }  
  
    @Override  
    public Integer getAge(int id) {  
        System.out.println("------getAge------");  
        return 10;  
    }  
}

代理的梁中國實現方式:JDK動態代理和cglib動態代理函數

JDK代理實現this

package com.meituan.hyt.test3.jdk;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
  
  
public class MyInvocationHandler implements InvocationHandler {  
    private Object target;  
  
    MyInvocationHandler() {  
        super();  
    }  
  
    MyInvocationHandler(Object target) {  
        super();  
        this.target = target;  
    }  
  
    @Override  
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {  
        if("getName".equals(method.getName())){  
            System.out.println("++++++before " + method.getName() + "++++++");  
            Object result = method.invoke(target, args);  
            System.out.println("++++++after " + method.getName() + "++++++");  
            return result;  
        }else{  
            Object result = method.invoke(target, args);  
            return result;  
        }  
  
    }  
}  

package com.meituan.hyt.test3.jdk;  
  
import com.meituan.hyt.test3.service.UserService;  
import com.meituan.hyt.test3.service.impl.UserServiceImpl;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  
  
  
public class Main1 {  
    public static void main(String[] args) {  
        UserService userService = new UserServiceImpl();  
        InvocationHandler invocationHandler = new MyInvocationHandler(userService);  
        UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),  
                userService.getClass().getInterfaces(), invocationHandler);  
        System.out.println(userServiceProxy.getName(1));  
        System.out.println(userServiceProxy.getAge(1));  
    }  
}

運行結果:spa

++++++before getName++++++
------getName------
++++++after getName++++++
Tom
------getAge------
10

================================================代理

Cglib代理實現code

Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類,使用CGLIB即便代理類沒有實現任何接口也能夠實現動態代理功能。CGLIB具備簡單易用,它的運行速度要遠遠快於JDK的Proxy動態代理:

CGLIB的核心類:
    net.sf.cglib.proxy.Enhancer – 主要的加強類
    net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,須要用戶實現
    net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,能夠方便的實現對源對象方法的調用,如使用:
    Object o = methodProxy.invokeSuper(proxy, args);//雖然第一個參數是被代理對象,也不會出現死循環的問題。

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它常常被基於代理的AOP用來實現攔截(intercept)方法的調用。這個接口只定義了一個方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;

第一個參數是代理對像,第二和第三個參數分別是攔截的方法和方法的參數。原來的方法可能經過使用java.lang.reflect.Method對象的通常反射調用,或者使用 net.sf.cglib.proxy.MethodProxy對象調用。net.sf.cglib.proxy.MethodProxy一般被首選使用,由於它更快。對象

import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
  
public class CglibProxy implements MethodInterceptor {  
    @Override  
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
        System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");  
        System.out.println(method.getName());  
        Object o1 = methodProxy.invokeSuper(o, args);  
        System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");  
        return o1;  
    }  
}  

import com.meituan.hyt.test3.service.UserService;  
import com.meituan.hyt.test3.service.impl.UserServiceImpl;  
import net.sf.cglib.proxy.Enhancer;  
  
  
  
public class Main2 {  
    public static void main(String[] args) {  
        CglibProxy cglibProxy = new CglibProxy();  
  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(UserServiceImpl.class);  
        enhancer.setCallback(cglibProxy);  
  
        UserService o = (UserService)enhancer.create();  
        o.getName(1);  
        o.getAge(1);  
    }  
}

運行結果:

++++++before CGLIB$getName$0++++++
getName
------getName------
++++++before CGLIB$getName$0++++++
++++++before CGLIB$getAge$1++++++
getAge
------getAge------
++++++before CGLIB$getAge$1++++++
相關文章
相關標籤/搜索