java動態代理淺析


最近在公司看到了mybatis與spring整合中MapperScannerConfigurer的使用,該類通過反向代理自動生成基於接口的動態代理類。

於是想起了java的動態代理,然后就有了這篇文章。

本文使用動態代理模擬處理事務的攔截器。

接口:

public interface UserService {
    public void addUser();
    public void removeUser();
    public void searchUser();
}

實現類:

public class UserServiceImpl implements UserService {
    public void addUser() {
        System.out.println("add user");
    }
    public void removeUser() {
        System.out.println("remove user");
    }
    public void searchUser() {
        System.out.println("search user");
    }
}

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

1.jdk自帶的動態代理

使用jdk自帶的動態代理需要了解InvocationHandler接口和Proxy類,他們都是在java.lang.reflect包下。

InvocationHandler介紹:

InvocationHandler是代理實例的調用處理程序實現的接口。

每個代理實例都具有一個關聯的InvocationHandler。對代理實例調用方法時,這個方法會調用InvocationHandler的invoke方法。

Proxy介紹:

Proxy 提供靜態方法用於創建動態代理類和實例。

實例(模擬AOP處理事務):

public class TransactionInterceptor implements InvocationHandler {

    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("start Transaction");
        method.invoke(target, args);
        System.out.println("end Transaction");
        return null;
    }

}

測試代碼:

public class TestDynamicProxy {

    @Test
    public void testJDK() {
        TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
        UserService userService = new UserServiceImpl();
        transactionInterceptor.setTarget(userService);
        UserService userServiceProxy =
                (UserService) Proxy.newProxyInstance(
                        userService.getClass().getClassLoader(),
                        userService.getClass().getInterfaces(),
                        transactionInterceptor);
        userServiceProxy.addUser();
    }

}

測試結果:

start Transaction
add user
end Transaction

很明顯,我們通過userServiceProxy這個代理類進行方法調用的時候,會在方法調用前后進行事務的開啟和關閉。

2. 第三方庫cglib

CGLIB是一個功能強大的,高性能、高質量的代碼生成庫,用於在運行期擴展Java類和實現Java接口。

它與JDK的動態代理的之間最大的區別就是:

JDK動態代理是針對接口的,而cglib是針對類來實現代理的,cglib的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。

實例:

public class UserServiceCallBack implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("start Transaction by cglib");
        methodProxy.invokeSuper(o, args);
        System.out.println("end Transaction by cglib");
        return null;
    }

}

測試代碼:

public class TestDynamicProxy {

    @Test
    public void testCGLIB() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(new UserServiceCallBack());
        UserServiceImpl proxy = (UserServiceImpl)enhancer.create();
        proxy.addUser();
    }

}

測試結果:

start Transaction by cglib
add user
end Transaction by cglib

結束語

簡單講解了JDK和cglib這2個動態代理,之后會再寫篇文章講講MapperScannerConfigurer的原理實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM