1. 程式人生 > >java動態代理的兩種實現方式

java動態代理的兩種實現方式

  一說到動態代理,我們第一個想到肯定是大名鼎鼎的Spring AOP了。在AOP的原始碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理是通過繼承來實現的,底層則是藉助asm(Java 位元組碼操控框架)來實現的(採用位元組碼的方式,給A類建立一個子類B,子類B使用方法攔截的技術攔截所以父類的方法呼叫)。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之後的相關執行過程中比較高效(可以通過將asm生成的類進行快取,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的介面。如果沒有上述前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的侷限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。。


  公用的介面和實現類

public interface UserService {
	public String getName(int id);

    public Integer getAge(int id);
}
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的動態代理實現

  jdk的動態代理,依賴的是反射包下的invocationHandler介面,我們的代理類實現invocationHandler,重寫invoke()方法,每當我們的代理類呼叫方法時,都會預設先經過invoke()方法。

public class UserInvocationHandler implements InvocationHandler {
    private Object target;

    UserInvocationHandler() {
        super();
    }

    UserInvocationHandler(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;
        }

    }
}

測試類
public class M {
	public static void main(String[] args) {
		UserService userService = new UserServiceImpl();
		InvocationHandler invocationHandler = new UserInvocationHandler(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));
	}
}
測試效果

CGLIB的動態代理實現

  cglib依賴的是cglib包下的methodInterceptor介面,每呼叫代理類的方法,都會呼叫intercept方法
public class CglibMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("------before " + methodProxy.getSuperName() + "------");
        Object o1 = methodProxy.invokeSuper(o, args);
        System.out.println("------after " + methodProxy.getSuperName() + "------");
        return o1;
    }
}


測試類
public class M {
	public static void main(String[] args) {
		CglibMethodInterceptor cglibProxy = new CglibMethodInterceptor();

		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(UserServiceImpl.class);
		enhancer.setCallback(cglibProxy);

		UserService o = (UserService) enhancer.create();
		o.getName(1);
		o.getAge(1);
	}
}
測試結果