代理實現機制,Java中動態代理和cglib動態代理的實現機制

代理是Java中一種常見的設計模式,代理不能夠直接訪問的類,通過代理類實現對內部
不能夠直接訪問的類的方法的調用,其特徵是代理類與需要代理的類(委託類)具有相同
的功能,甚至是同一個接口的實現類。按照代理類存在的時期分爲靜態代理和動態代理兩類。

靜態代理:由程序創建生成源碼,再對其進行編譯,在程序運行前class文件已經存在。

動態代理:在程序運行的時候通過反射機制創建。

靜態代理例子:

package core.java.proxy.stac;

public interface ProductService {
	
	public void detail(String productNo);

}

package core.java.proxy.stac;

public class ProductServiceImpl implements ProductService{

	@Override
	public void detail(String productNo) {
		System.out.println("這是編號爲" + productNo + "的詳細數據");
		
	}

}

package core.java.proxy.stac;

public class ProductProxy implements ProductService{
	
	private ProductServiceImpl productService;
	
	public ProductProxy(ProductServiceImpl productServiceImpl){
		this.productService = productServiceImpl;
	}

	@Override
	public void detail(String productNo) {
		System.out.println("product proxy before.............");
		productService.detail(productNo);
		System.out.println("product proxy after.............");
	}

}

package core.java.proxy.stac;

public class StacProxyTest {
	
	public static void main(String[] args) {
		ProductProxy proxy = new ProductProxy(new ProductServiceImpl());
		proxy.detail("30001245");
	}
}
輸出結果:
product proxy before.............
這是編號爲30001245的詳細數據
product proxy after.............

由上面的例子可以看出靜態代理類其實是對實現類的引用然後再對其方法進行調用,
並且靜態代理類只能爲一個類服務,如果有很多類需要代理就會創建很多代理類,
代碼中出現大量的代理類。


爲了解決靜態代理帶來的不便,Java中提供了動態代理的實現機制,如果想創建代理類
只需要實現InvocationHandler接口,實現其invoke方法即可。

Java動態代理實現例子:

package core.java.proxy;


/**
 * 實現的業務接口
 * @author admin
 *
 */
public interface UserService {
	
	public void sayHello(String name);

}

package core.java.proxy;


/**
 * 實際業務的實現類
 * @author admin
 *
 */
public class UserServiceImpl implements UserService{

	@Override
	public void sayHello(String name) {
		System.out.println("hello " + name + "!");
	}

}

package core.java.proxy;

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


/**
 * 業務代理類
 * @author admin
 *
 */
public class UserProxy implements InvocationHandler{
	
	/**
	 * 需要代理的原生對象
	 */
	private Object obj;
	
	public UserProxy(Object obj) {
		super();
		this.obj = obj;
	}

	/**
	 * @param proxy 被代理的對象
	 * @param method 需要調用的方法
	 * @param args  方法調用時需要的參數
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("proxy before..........");
		Object result = method.invoke(obj, args);
		System.out.println("proxy after............");
		return result;
	}
}

package core.java.proxy;

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


public class ProxyTest {
	
	public static void main(String[] args) {
		UserService userService = new UserServiceImpl();
		InvocationHandler invocationHandler = new UserProxy(userService);
		UserService proxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
		proxy.sayHello("zhangsan");
	}

}
輸出結果:
proxy before..........
hello zhangsan!
proxy after............

動態代理可以實現所有需要代理的原生類的功能,解決了靜態代理的缺陷。但是動態代理
也有自身的缺陷,就是動態代理只能代理有實現類的接口,這就需要代理的接口類必須有
實現類,這樣程序中也會出現大量的實現類,爲了解決這一缺陷,cglib就是對這一缺陷
的彌補。cglib的原理就是對目標類生成一個子類,覆蓋其方法進行增強。因爲採用的是
Java中繼承的機制,因此不能對用了final修飾符的類進行代理。


cglib動態代理例子:

package core.java.proxy.cglib;

public interface TicketService {
	
	public void sell();

}

package core.java.proxy.cglib;

public class TicketBiz {
	
	public void sell(){
		System.out.println("賣出一張票");
	}

}

package core.java.proxy.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 ProxyCglib implements MethodInterceptor{
	
	private Object target;
	
	public Object createProxy(Object target){
		this.target = target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.target.getClass());
		enhancer.setCallback(this);
		enhancer.setClassLoader(this.getClass().getClassLoader());
		return enhancer.create();
	}

	@Override
	public Object intercept(Object arg, Method method, Object[] objects,
			MethodProxy proxy) throws Throwable {
		System.out.println("sell ticket before..........");
		proxy.invokeSuper(arg, objects);
		System.out.println("sell ticket after..........");
		return null;
	}

}

package core.java.proxy.cglib;


public class CglibProxyTest {
	
	public static void main(String[] args) {
		ProxyCglib proxyCglib = new ProxyCglib();
		TicketBiz ticketBiz = (TicketBiz)proxyCglib.createProxy(new TicketBiz());
		ticketBiz.sell();
	}

}
輸出結果:
sell ticket before..........
賣出一張票
sell ticket after..........


靜態代理和動態代理比較:
靜態代理預先生成好代理類通過編譯生成class文件,程序運行時就能調用,
動態代理是程序運行時根據反射機制生成代理類,因此靜態代理的速度要
比動態代理快一些。



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