小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

從mybatis源碼看JDK動(dòng)態(tài)代理

 Coder編程 2020-05-25

網(wǎng)上好多說(shuō)到動(dòng)態(tài)代理的文章內(nèi)容都是這樣子的:

一個(gè)實(shí)際干事的類Real;一個(gè)被創(chuàng)造的代理類Proxy。

Proxy調(diào)用Real中被代理的方法;有模有樣的在被代理的方法前后打印出一些字符串。

比如下面的例子:

 1 public class JdkProxy {
 2     static interface IProxy{
 3         String say(String s);
 4     }
 5     static class Real implements IProxy{
 6         @Override
 7         public String say(String s) {
 8             System.out.println("說(shuō)完了,返回結(jié)果");
 9             return s;
10         }
11     }   
12 
13     static class MyInvocationHandler implements  InvocationHandler{
14         private Object real;
15 
16         public MyInvocationHandler(Object real) {
17             this.real = real;
18         }
19 
20         @Override
21         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
22             Object res=null;
23             if(method.getName().equals("say")){
24                 System.out.println("say start...");
25                 res=method.invoke(real,args);
26                 System.out.println("say end...");
27             }
28             return res;
29         }
30     }    
31 
32     public static void main(String[] args) {
33         execu1();      
34     }
35 
36     private static void execu1(){
37         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
38         Real real=new Real();
39         IProxy proxy=(IProxy) Proxy.newProxyInstance(real.getClass().getClassLoader(), real.getClass().getInterfaces(),new MyInvocationHandler(real));
40         String s=proxy.say("abc");
41         System.out.println(s);
42     }   
43 
44 }

上面21-27行代碼是調(diào)用被代理的方法;

如果我現(xiàn)在不調(diào)用被代理的方法,而是直接寫一個(gè)方法體。

代碼如下:

 1 public class JdkProxy {
 2     static interface IProxy{
 3         String say(String s);
 4     }
 5     static class Real implements IProxy{
 6         @Override
 7         public String say(String s) {
 8             System.out.println("說(shuō)完了,返回結(jié)果");
 9             return s;
10         }
11     }   
12 
13     static class MyInvocationHandler implements  InvocationHandler{
14         private Object real;
15 
16         public MyInvocationHandler(Object real) {
17             this.real = real;
18         }
19 
20         @Override
21         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
22            return "我什么也不代理,我直接就是一個(gè)方法";
23         }
24     }    
25 
26     public static void main(String[] args) {
27         execu1();      
28     }
29 
30     private static void execu1(){
31         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
32         Real real=new Real();
33         IProxy proxy=(IProxy) Proxy.newProxyInstance(IProxy.class.getClassLoader(),new Class[]{IProxy.class},new MyInvocationHandler(real));
34         String s=proxy.say("abc");
35         System.out.println(s);
36     }   
37 
38 }

改動(dòng)代碼是22行的代碼。

如果不需要被代理的方法了,那么還需要實(shí)際干活的類嗎?

繼續(xù)修改代碼:

 1 public class JdkProxy {
 2     static interface IProxy{
 3         String say(String s);
 4     }   
 5 
 6     static class MyInvocationHandler implements  InvocationHandler{
 7         
 8 
 9         @Override
10         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
11            return "我什么也不代理,我直接就是一個(gè)方法";
12         }
13     }    
14 
15     public static void main(String[] args) {
16         execu1();      
17     }
18 
19     private static void execu1(){
20         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");      
21         IProxy proxy=(IProxy) Proxy.newProxyInstance(IProxy.class.getClassLoader(),new Class[]{IProxy.class},new MyInvocationHandler());
22         String s=proxy.say("abc");
23         System.out.println(s);
24     } 
25 }

 上面的程序依然能夠正常運(yùn)行。

從這個(gè)層面來(lái)說(shuō),動(dòng)態(tài)代理就是給我們創(chuàng)造了一個(gè)類,至于有沒(méi)有實(shí)際干活的類無(wú)關(guān)。

網(wǎng)上到處都在說(shuō)mybatis接口編程的用的是動(dòng)態(tài)代理,創(chuàng)造代理類我們很好理解,那么他到底代理了什么類呢?

先來(lái)個(gè)簡(jiǎn)單的mybatis例子:

1 SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
2 SqlSession sqlSession= sqlSessionFactory.openSession();
3 IRoleMapper iRoleMapper=sqlSession.getMapper(IRoleMapper.class);
4 List<Role> list=iRoleMapper.getRole(1L);

第三行代碼就應(yīng)該是獲取代理的過(guò)程;iRoleMapper指向具體的代理類。

下面查看源碼:

getMapper()源碼:

 1  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
 2     final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
 3     if (mapperProxyFactory == null) {
 4       throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
 5     }
 6     try {
 7       return mapperProxyFactory.newInstance(sqlSession);
 8     } catch (Exception e) {
 9       throw new BindingException("Error getting mapper instance. Cause: " + e, e);
10     }
11   }

代碼比較簡(jiǎn)潔,代理類是在第7行生成的。進(jìn)入newInstance()方法:

newInstance()源碼:

1 protected T newInstance(MapperProxy<T> mapperProxy) {
2     return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
3   }
4 
5   public T newInstance(SqlSession sqlSession) {
6     final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
7     return newInstance(mapperProxy);
8   }

第1行的newInstance調(diào)用的是JDK的代理方法

第5行的newInstance是Mybatis自己的方法,根據(jù)JDK動(dòng)態(tài)代理的調(diào)用規(guī)則,第6行的MapperProxy一定繼承了InvocationHandler接口,并且實(shí)現(xiàn)了接口方法invoke();

invoke()源碼

 1  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 2     try {
 3       if (Object.class.equals(method.getDeclaringClass())) {
 4         return method.invoke(this, args);
 5       } else if (method.isDefault()) {
 6         if (privateLookupInMethod == null) {
 7           return invokeDefaultMethodJava8(proxy, method, args);
 8         } else {
 9           return invokeDefaultMethodJava9(proxy, method, args);
10         }
11       }
12     } catch (Throwable t) {
13       throw ExceptionUtil.unwrapThrowable(t);
14     }
15     final MapperMethod mapperMethod = cachedMapperMethod(method);
16     return mapperMethod.execute(sqlSession, args);
17   }

invoke()方法體中并沒(méi)有調(diào)用    res=method.invoke(real,args);這類的代碼。說(shuō)明一個(gè)問(wèn)題,這里并沒(méi)有我們常說(shuō)的Real這樣的類。

總結(jié):

1.JDK動(dòng)態(tài)代理只是需要一個(gè)接口,至于實(shí)際干活類不是必須的;至于具體做什么,由程序員在invoke()中去實(shí)現(xiàn)。

2.Mybatis用了JDK動(dòng)態(tài)代理,但是并沒(méi)有提供被代理的類;只是提供了一個(gè)代理類或者干脆說(shuō)提供了一個(gè)我們看不見(jiàn)的類用于執(zhí)行Sql

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多