看mybatis日誌模組時涉及的動態代理
阿新 • • 發佈:2021-01-11
動態代理的使用和個人理解(再看spring aop前的理解)
動態代理呼叫一個方法,並且對這個方法進行增強,程式碼如下
程式碼如下,
- //介面
1packagecom.enjoylearning.proxy.unknow;
2
3publicinterfaceUnknowToolsFactory{
4voidsaleUnknowTools(floatlength);
5}
- 介面實現
1packagecom.enjoylearning.proxy.unknow;
2
3publicclassDdFactoryimplementsUnknowToolsFactory{
4@Override
5publicvoidsaleUnknowTools(floatlength){
6System.out.println("根據您的需求,為您定製了一個高度為:\"+length+\"的Unknow模特");
7}
8}
- 動態代理類
1packagecom.enjoylearning.proxy.unknow;
2
3importjavax.annotation.Resource;
4importjava.lang.reflect.InvocationHandler;
5importjava.lang.reflect.Method;
6importjava.lang.reflect.Proxy;
7
8publicclassLicmCompanyimplementsInvocationHandler{
9
10@Resource
11privateObjectfactory;
12
13publicObjectgetFactory(){
14returnfactory;
15}
16
17publicvoidsetFactory(Objectfactory){
18this.factory=factory;
19}
20
21publicObjectgetProxyInstance(){
22returnProxy.newProxyInstance(factory.getClass().getClassLoader(),factory.getClass().getInterfaces(),this );
23}
24
25
26@Override
27publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
28dosomeThingBefore();
29Objectobj=method.invoke(factory,args);
30dosomeThingEnd();
31returnobj;
32}
33
34//售前服務
35privatevoiddosomeThingEnd(){
36System.out.println("精美包裝,快遞一條龍服務!");
37}
38
39//售後服務
40privatevoiddosomeThingBefore(){
41System.out.println("根據您的需求,進行市場調研和產品分析!");
42}
43}
- 測試類,普通的main方法
1UnknowToolsFactoryunknowToolsFactory=newDdFactory();
2LicmCompanylicmCompany=newLicmCompany();
3licmCompany.setFactory(unknowToolsFactory);
4UnknowToolsFactorylicm2=(UnknowToolsFactory)licmCompany.getProxyInstance();
5licm2.saleUnknowTools(1.2f);
- 附一個工具類,動態生成的二進位制位元組碼儲存到硬碟中
1packagecom.enjoylearning.proxy.utils;
2
3importjava.io.FileOutputStream;
4importjava.io.IOException;
5importjava.lang.reflect.Proxy;
6importsun.misc.ProxyGenerator;
7
8publicclassProxyUtils{
9
10/*
11*將根據類資訊動態生成的二進位制位元組碼儲存到硬碟中,預設的是clazz目錄下params:clazz需要生成動態代理類的類
12*proxyName:為動態生成的代理類的名稱
13*/
14publicstaticvoidgenerateClassFile(Classclazz,StringproxyName){
15
16
17//根據類資訊和提供的代理類名稱,生成位元組碼
18byte[]classFile=ProxyGenerator.generateProxyClass(proxyName,
19newClass[]{clazz});
20
21Stringpaths=clazz.getResource(".").getPath();
22System.out.println(paths);
23FileOutputStreamout=null;
24
25try{
26//保留到硬碟中
27out=newFileOutputStream(paths+proxyName+".class");
28//out=newFileOutputStream("C:/a.class");
29out.write(classFile);
30out.flush();
31}catch(Exceptione){
32e.printStackTrace();
33}finally{
34try{
35out.close();
36}catch(IOExceptione){
37e.printStackTrace();
38}
39}
40}
41
42}
需要注意的幾個方法
- 程式碼結構,需要一個介面,實現類,實現invocationhandler的代理類
- 代理類中的public Object invoke(Object proxy, Method method, Object[] args) 的三個引數,
- 代理的真實物件(本文中的Ddfactory)
- 呼叫的真實方法 (saleUnknowTools)
- 呼叫的真實方法傳入的引數 (licm2.saleUnknowTools(1.2f))
- 一般在invoke中,會對執行方法進行增強,比如method,invoke前後加入新的方法
- proxy 這個類深入說一下
- Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 動態建立一個代理類物件
- 這個類最常用的是 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
- 類載入器,由那個類載入器物件對生成的代理類進行載入,一般為出入的實現類的介面物件(UnknowToolsFactory,一般為factory.getclass.getclassloader)
- 介面的實現類 factory.getclass.getinterfaces()
- 為實現invacationhandler的類