1. 程式人生 > 實用技巧 >[CF334D]Water Tree

[CF334D]Water Tree

什麼是代理?

  為某一個物件建立一個代理物件,程式不直接用原本的物件,而是由建立的代理物件來控制原物件,通過代理類這中間一層,能有效控制對委託類物件的直接訪問,也可以很好地隱藏和保護委託類物件,同時也為實施不同控制策略預留了空間

什麼是靜態代理?

  由程式建立或特定工具自動生成原始碼,在程式執行前,代理類的.class檔案就已經存在

  通過將目標類與代理類實現同一個介面,讓代理類持有真實類物件,然後在代理類方法中呼叫真實類方法,在呼叫真實類方法的前後新增我們所需要的功能擴充套件程式碼來達到增強的目的。

優點

  代理使客戶端不需要知道實現類是什麼,怎麼做,而客戶端只需知道代理即可

  方便增加功能,擴充套件業務邏輯

缺點

  代理類中常出現大量冗餘的程式碼,非常不利於擴充套件和維護

  如果介面增加一個方法,除了所有實現類需要實現這個方法外,所有代理類也需要實現此方法。增加了程式碼維護的複雜度

案例演示

PayService.java(介面)

package net.cybclass.sp.proxy;

public interface PayService {
/**
* 支付回撥
* @param outTradeNo 訂單號
* @return
*/
String callback(String outTradeNo); /**
* 下單
* @param userId 使用者id
* @param productId 產品id
* @return
*/
int save(int userId,int productId);
}

PayServiceImpl.java(介面實現類)

package net.cybclass.sp.proxy;

public class PayServiceImpl implements PayService{
public String callback(String outTradeNo) {
System.out.println("目標類 PayServiceImpl 回撥 方法 callback");
return outTradeNo;
} public int save(int userId, int productId) {
System.out.println("目標類 PayServiceImpl 回撥 方法 save");
return productId;
}
}

StaticProxyPayServiceImpl.java(介面實現類,靜態代理)

package net.cybclass.sp.proxy;

public class StaticProxyPayServiceImpl implements PayService{
private PayService payService;
public StaticProxyPayServiceImpl(PayService payService)
{
this.payService=payService;
}
public String callback(String outTradeNo) {
System.out.println("StaticProxyPayServiceImpl callback begin");
String result=payService.callback(outTradeNo);
System.out.println("StaticProxyPayServiceImpl callback end");
return result;
} public int save(int userId, int productId) {
System.out.println("StaticProxyPayServiceImpl save begin");
int id = payService.save(userId, productId);
System.out.println("StaticProxyPayServiceImpl save end");
return id;
}
}

演示

什麼是動態代理?

  在程式執行時,運用反射機制動態建立而成,無需手動編寫程式碼

    • JDK動態代理
    • CGLIB動態代理(原理:是對指定的業務類生成一個子類,並覆蓋其中的業務方法來實現代理)

jdk動態代理演示

定義一個類,去實現InvocationHandler這個介面,並車從寫invoke方法

//Object proxy:被代理的物件
//Method method:要呼叫的方法
//Object[] args:方法呼叫時所需要引數
public Object invoke(Object proxy, Method method, Object[] args){}

PayService.java(介面)

package net.cybclass.sp.proxy;

public interface PayService {
/**
* 支付回撥
* @param outTradeNo 訂單號
* @return
*/
String callback(String outTradeNo); /**
* 下單
* @param userId 使用者id
* @param productId 產品id
* @return
*/
int save(int userId,int productId);
}

PayServiceImpl.java(介面實現類)

package net.cybclass.sp.proxy;

public class PayServiceImpl implements PayService{
public String callback(String outTradeNo) {
System.out.println("目標類 PayServiceImpl 回撥 方法 callback");
return outTradeNo;
} public int save(int userId, int productId) {
System.out.println("目標類 PayServiceImpl 回撥 方法 save");
return productId;
}
}

JDKProxy.java(jdk動態代理類)

package net.cybclass.sp.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class JDKProxy implements InvocationHandler {
//目標類
private Object targetObject; /**
* 獲取代理物件
* @param targetObject 目標類
* @return
*/
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
//繫結關係,也就是和具體的那個實現類關聯
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
} /**
* JDK動態代理
*
* @param proxy 靜態代理物件
* @param method 要呼叫的方法
* @param args 方法呼叫時所需要引數
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
System.out.println("通過JDK動態代理呼叫"+method.getName()+",列印日誌 begin");
result = method.invoke(targetObject, args);
System.out.println("通過JDK動態代理呼叫"+method.getName()+",列印日誌 end");
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
}

演示

CGLIB動態代理演示

PayService.java(介面)

package net.cybclass.sp.proxy;

public interface PayService {
/**
* 支付回撥
* @param outTradeNo 訂單號
* @return
*/
String callback(String outTradeNo); /**
* 下單
* @param userId 使用者id
* @param productId 產品id
* @return
*/
int save(int userId,int productId);
}

PayServiceImpl.java(介面實現類)

package net.cybclass.sp.proxy;

public class PayServiceImpl implements PayService{
public String callback(String outTradeNo) {
System.out.println("目標類 PayServiceImpl 回撥 方法 callback");
return outTradeNo;
} public int save(int userId, int productId) {
System.out.println("目標類 PayServiceImpl 回撥 方法 save");
return productId;
}
}

CGLIBProxy.java(CGLIB動態代理類)

package net.cybclass.sp.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CGLIBProxy implements MethodInterceptor {
//目標類
private Object targetObject;
//繫結關係
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
Enhancer enhancer=new Enhancer();
//設定代理類的父類(目標類)
enhancer.setSuperclass(this.targetObject.getClass());
//設定回撥函式
enhancer.setCallback(this);
//建立子類(代理物件)
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result=null;
try
{
System.out.println("通過CGLIB動態代理呼叫"+method.getName()+",列印日誌 begin");
result=methodProxy.invokeSuper(o,args);
System.out.println("通過CGLIB動態代理呼叫"+method.getName()+",列印日誌 end");
}
catch (Exception ex){
ex.printStackTrace();
}
return result;
}
}

演示