1. 程式人生 > 實用技巧 >看mybatis日誌模組時涉及的動態代理

看mybatis日誌模組時涉及的動態代理

動態代理的使用和個人理解(再看spring aop前的理解)

動態代理呼叫一個方法,並且對這個方法進行增強,程式碼如下

程式碼如下,
  1. //介面
1packagecom.enjoylearning.proxy.unknow;
2
3publicinterfaceUnknowToolsFactory{
4voidsaleUnknowTools(floatlength);
5}
  1. 介面實現
1packagecom.enjoylearning.proxy.unknow;
2
3publicclassDdFactoryimplementsUnknowToolsFactory{
4@Override

5publicvoidsaleUnknowTools(floatlength){
6System.out.println("根據您的需求,為您定製了一個高度為:\"+length+\"的Unknow模特");
7}
8}
  1. 動態代理類
 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}
  1. 測試類,普通的main方法
1UnknowToolsFactoryunknowToolsFactory=newDdFactory();
2LicmCompanylicmCompany=newLicmCompany();
3licmCompany.setFactory(unknowToolsFactory);
4UnknowToolsFactorylicm2=(UnknowToolsFactory)licmCompany.getProxyInstance();
5licm2.saleUnknowTools(1.2f);
  1. 附一個工具類,動態生成的二進位制位元組碼儲存到硬碟中
 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}
需要注意的幾個方法
  1. 程式碼結構,需要一個介面,實現類,實現invocationhandler的代理類
  2. 代理類中的public Object invoke(Object proxy, Method method, Object[] args) 的三個引數,
  1. 代理的真實物件(本文中的Ddfactory)
  2. 呼叫的真實方法 (saleUnknowTools)
  3. 呼叫的真實方法傳入的引數 (licm2.saleUnknowTools(1.2f))
  4. 一般在invoke中,會對執行方法進行增強,比如method,invoke前後加入新的方法
  1. proxy 這個類深入說一下
  1. 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. 動態建立一個代理類物件
  2. 這個類最常用的是 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
  1. 類載入器,由那個類載入器物件對生成的代理類進行載入,一般為出入的實現類的介面物件(UnknowToolsFactory,一般為factory.getclass.getclassloader)
  2. 介面的實現類 factory.getclass.getinterfaces()
  3. 為實現invacationhandler的類