java動態代理和cglib動態代理

動態代理應用廣泛,Spring,Struts等框架很多功能是通過動態代理,或者進一步封裝來實現的。

常見的動態代理模式實現有Java API提供的動態代理和第三方開源類庫CGLIB動態代理。

Java API提供的動態代理是基於類反射實現的,用到的類有:

java.lang.reflect.InvocationHandler;

java.lang.reflect.Method;

java.lang.reflect.Proxy;

其實現是通過Proxy類的newProxyInstance()方法產生代理對象。自定義動態代理類需要實現InvocationHandler接口,該接口只有一個invoke()方法。


CGLIB是通過生成java 字節碼從而動態的產生代理對象,因此需要字節碼解析處理的依賴asm類庫,字節碼動態生成的代理對象實際上是繼承了真實主題類的。這種實現方式需要導入cglib和asm的類庫。下面用到的例子是cglib-2.2.2.jar, asm-3.3.1.jar。cglib使用了MethodInterceptor,其中的方法是intercept(),這是攔截的概念,很容易就想到了Struts2的攔截器。

比較之下,Java API提供的動態代理需要面向接口,產生代理對象,因此真實主題實現類必須實現了接口纔可以。而CGLIB不需要面向接口,可以代理簡單類,但由於動態代理對象是繼承真實主題實現類的,因此要求真實主題實現類不能是final的。

下面是實現的例子。

首先,爲了看到動態代理可以根據不同類動態產生不同代理的效果,我們新建兩個接口,及其實現類。

package leon.aj.dynproxy.target;

public interface Hello {
	public String sayHello(String name);
}
實現類:

package leon.aj.dynproxy.target;

public class HelloImpl implements Hello {
	@Override
	public String sayHello(String name) {
		String s = "Hello, "+name;
		System.out.println(this.getClass().getName()+"->"+s);
		return s;
	}
}
另一接口和實現類:

package leon.aj.dynproxy.target;

public interface UserDao {
	public boolean login(String username,String password);
}

package leon.aj.dynproxy.target;

public class UserDaoImpl implements UserDao {
	@Override
	public boolean login(String username, String password) {
		String user = "("+username+","+password+")";
		System.out.println(this.getClass().getName()+"-> processing login:"+user);
		return true;
	}
}

應用Java API實現的動態代理類:

package leon.aj.dynproxy.java;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JavaDynProxy implements InvocationHandler{
	private Object target;
	public Object getProxyInstance(Object target){
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result = null;
		System.out.println("before target method...");
		result = method.invoke(target, args);
		System.out.println("after target method...");
		return result;
	}
}

測試:

package leon.aj.dynproxy.java;

import leon.aj.dynproxy.target.Hello;
import leon.aj.dynproxy.target.HelloImpl;
import leon.aj.dynproxy.target.UserDao;
import leon.aj.dynproxy.target.UserDaoImpl;

public class TestJavaProxy {
	public static void main(String[] args) {
		JavaDynProxy proxy = new JavaDynProxy();
		Hello hello = (Hello)proxy.getProxyInstance(new HelloImpl());
		String s = hello.sayHello("Leon");
		System.out.println(s);
		
		UserDao userDao = (UserDao) proxy.getProxyInstance(new UserDaoImpl());
		userDao.login("Leon", "1234");
		System.out.println(userDao.getClass().getName());
	}
}

下面是採用cglib實現的例子:

package leon.aj.dynproxy.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {
	private Object target;  
	
    public Object getProxyInstance(Object target) {  
    	this.target = target;
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        enhancer.setCallback(this);  // call back method
        return enhancer.create();  // create proxy instance
    }  
	
	@Override
	public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("before target method...");
		Object result = proxy.invokeSuper(target, args);
		System.out.println("after target method...");
		return result;
	}
}

測試類:

package leon.aj.dynproxy.cglib;

import leon.aj.dynproxy.target.Hello;
import leon.aj.dynproxy.target.HelloImpl;
import leon.aj.dynproxy.target.UserDaoImpl;

public class TestCiglib {
	public static void main(String[] args) {
		CglibProxy proxy = new CglibProxy();
		Hello hello = (Hello) proxy.getProxyInstance(new HelloImpl());
		System.out.println(hello.sayHello("Leon"));
		UserDaoImpl userDao = (UserDaoImpl) proxy.getProxyInstance(new UserDaoImpl());
		userDao.login("Leon", "1234");
		System.out.println(userDao.getClass().getSuperclass());//看動態代理實例的父類
	}
}












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章