Erlang那些事兒第3回之我是函式(fun),萬物之源MFA
阿新 • • 發佈:2021-01-03
技術標籤:動態代理
動態代理
一.動態代理特點
位元組碼隨用隨建立,隨用隨載入。它與靜態代理的區別也在於此。因為靜態代理是位元組碼一上來就建立好,並完成載入。裝飾者模式就是靜態代理的一種體現。
二.動態代理方式
1.基於介面的動態代理
提供者:JDK 官方的 Proxy 類。
要求:被代理類最少實現一個介面。
2.基於子類的動態代理
提供者:第三方的 CGLib,如果報 asmxxxx 異常,需要匯入 asm.jar。
要求:被代理類不能用 final 修飾的類(最終類)。
三.基於介面的動態代理的實現案例
1.提供一個介面:
2.提供一個實現類:
package com.xszx. dynamicProxy.baseInte;
/**
* @author Mr Z
*
*
* 廠家
*/
public class Producer implements ProducerInte {
public void salProduct(float money) {
System.out.println("銷售產品,收錢"+money);
}
public void afterService(float money) {
System.out.println("提供售後服務,收錢" +money);
}
}
3.實現過程
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Mr Z
*
* 顧客
*
* newProxyInstance方法的引數:
* ClassLoader:類載入器
* 它是用於載入代理物件位元組碼;和被代理物件使用相同的類載入器。
* Class[]:位元組碼陣列
* 用於讓代理物件和被代理物件有相同的方法
* InvocationHandler:用於提供增強的程式碼。
* 寫如何代理,通常使用匿名內部類
*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
ProducerInte producerInte = (ProducerInte) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 作用:執行被代理物件的任何介面方法都會經過該方法
* @param proxy 代理物件的引用
* @param method 當前執行的方法
* @param args 當前執行方法所需引數
* @return 和被代理物件有相同的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//提供增強程式碼
Object returnValue=null;
//1.獲取方法執行的引數
Float money=(Float)args[0];
//2.判斷當前的方法是否為銷售
if ("saleProduct".equals(method.getName())){
returnValue=method.invoke(producer,money*0.8f);
System.out.println("經銷商賺取差價:"+money*0.2f);
}
return returnValue;
}
});
producerInte.saleProduct(1000);
}
}
四.基於子類的動態代理
1.匯入第三方jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2.介面和實現類同上
3.實現程式碼
import com.xszx.dynamicProxy.baseInte.Producer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author Mr Z
* @create 2021 01 2021/1/6 16:52
* 顧客
*
* create方法的引數:
* Class:位元組碼
* 它是用於指定被代理物件位元組碼
* Callback:用於提供增強的程式碼
* 一般寫該介面的子介面實現類:MethodInterceptor
*/
public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
Producer cglibproducer= (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
*
* @param proxy
* @param method
* @param args
* 以上三個引數和基於介面的動態代理的引數相同
* @param methodProxy 當前執行方法代理物件
* @return
* @throws Throwable
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//提供增強程式碼
Object returnValue=null;
//1.獲取方法執行的引數
Float money=(Float)args[0];
//2.判斷當前的方法是否為銷售
if ("saleProduct".equals(method.getName())){
returnValue=method.invoke(producer,money*0.8f);
System.out.println("經銷商賺取差價:"+money*0.2f);
}
return returnValue;
}
});
cglibproducer.saleProduct(1000f);
}
}