Aujourd'hui, par hasard, j'ai eu envie de jeter un œil au proxy dynamique du JDK, car je le connaissais un peu avant, et je voulais juste tester son utilisation. J'ai écrit plusieurs interfaces et classes en peu de temps. :
Classe d'interface : UserService.java
package com.yixi.proxy; public interface UserService { public int save() ; public void update(int id); }
Classe d'implémentation : UserServiceImpl.java
package com.yixi.proxy; public class UserServiceImpl implements UserService { @Override public int save() { System.out.println("user save...."); return 1; } @Override public void update(int id) { System.out.println("update a user " + id); } }
Ensuite, j'ai rapidement écrit l'InvocationHandler que je voulais : La fonction de ceci est C'est très simple d'enregistrer l'heure de début et l'heure de fin d'exécution de la méthode
TimeInvocationHandler.java
package com.yixi.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(proxy, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; } }
Une fois tous les préparatifs terminés, il est bien sûr temps de commencer à écrire des tests !
Test.java
package com.yixi.proxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { 9 TimeInvocationHandler timeHandler = new TimeInvocationHandler(); UserService u = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler); u.update(2); u.save(); } }
Exécutez joyeusement, mais cela ne vous donne pas la face. Le résultat est une exception qui remplit l'écran :
startTime : 1352877835040 startTime : 1352877835040 startTime : 1352877835040 Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at $Proxy0.update(Unknown Source) at com.yixi.proxy.Test.main(Test.java:11) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12) ... 2 more
com.yixi.proxy. . L'exception TimeInvocationHandler.invoke(TimeInvocationHandler.java:12) nous indique clairement que le problème se situe dans la ligne 12 de TimeInvocationHandle : c'est-à-dire
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(proxy, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; }Il n'y a rien de mal dans la méthode ! Parce que la méthode Invoke() semble fournir tous les paramètres requis par method.invoke(Object, Object[]), nous l'utiliserons naturellement. Si vous pensez vraiment de cette façon, alors vous avez trompé le JDK. un piège, regardons d'abord la bonne façon d'écrire. Au cas où certains étudiants ne seraient pas d'humeur à lire ce qui suit, donnez-moi au moins la bonne solution :
Modify TimeInvocationHandler.java
package com.yixi.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeInvocationHandler implements InvocationHandler { private Object o; public TimeInvocationHandler(Object o){ this.o = o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(o, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; } }
Modifier Test.java
package com.yixi.proxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { TimeInvocationHandler timeHandler = new TimeInvocationHandler(new UserServiceImpl()); UserService u = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler); u.update(2); u.save(); } }
Voici le résultat correct maintenant :
startTime : 1352879531334 update a user 2 endTime : 1352879531334 startTime : 1352879531334 user save.... endTime : 1352879531335
Si vous souhaitez utiliser moins de code, vous pouvez écrire directement une classe anonyme :
package com.yixi.proxy;
import java .lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
classe publique Test {
public static void main(String[] args ) {
final UserServiceImpl usi = new UserServiceImpl();
UserService u = (UserService) Proxy.newProxyInstance(
usi.getClass(). getClassLoader(),
usi.getClass().getInterfaces (),
new InvocationHandler() {
@Override
public Object Ensure (Object proxy, method, Object[] Method args)
lance Throwable {
startTime : " System.currentTimeMillis());
Object obj = method.invoke(usi, args);
System.out.println("endTime : " System.currentTimeMillis() );
Return obj ;
} voke(target,args) Le premier paramètre dans ; Le gestionnaire a-t-il besoin d'un paramètre de proxy d'objet ? Regardons en bas !
Pour la méthode d'invocation la plus importante (à mon avis), jetons un œil à ce que dit le JDK :
proxy - l'instance proxy sur laquelle la méthode est appelée ? Que signifie cette phrase ? par intérim? La méthode est-elle la méthode proxy ? Alors ma méthode pour exécuter le proxy ne devrait-elle pas être Object obj = method.invoke(proxy, args);? Je ne me suis pas retourné à ce moment-là, je suis allé au groupe de discussion et je suis allé sur Google mais je n'ai trouvé aucune inspiration. J'ai pensé que je ferais mieux de regarder le code source et peut-être que je pourrais voir quelque chose !
Ouvrez le code source de la classe Proxy et découvrez quel type de méthode de construction il existe :
invoke Object invoke(Object proxy, Method method, Object[] args) throws Throwable在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。 参数: proxy - 在其上调用方法的代理实例 method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。 args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。Ma première pensée est que Proxy appellera l'instruction suivante en interne :
Parce que vous devez appeler la méthode d'invocation pour exécuter la méthode correspondante
protected InvocationHandler h; protected Proxy(InvocationHandler h) { this.h = h; }Jetons un coup d'œil à cela d'abord <.>
在这里你就会发现貌似有点感觉了:当u.update(2)时 àProxy就会调用 handler.invoke(proxyClass,update,2) à 也就是调用了proxyClass.update(2);
当u.save();时àProxy就会调用handler.invoke(proxyClass,save,null) à也就是调用了proxyClass.save();
当Test.java改成这样时:
public class Test { public static void main(String[] args) { final UserServiceImpl usi = new UserServiceImpl(); UserService u = (UserService) Proxy.newProxyInstance( usi.getClass().getClassLoader(), usi.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }); u.update(2); u.save(); } }
注意这时候的匿名类的方法的返回的是null,运行一下就会发现:
Exception in thread "main" java.lang.NullPointerException at $Proxy0.save(Unknown Source) at com.yixi.proxy.Test.main(Test.java:17)
17行有空指针 也就是这里的u.save()方法有为null的元素 难道是u是空的? 不应该啊如果u是null的话那么u.update(2)在那里就会报空指针异常了,当我把17行注释掉以后异常没了说明u.update()能正常执行。那这到底是为什么呢?
其实这就是invoke方法返回null的缘故:
注意一下UserService类中的两个方法:
public interface UserService { public int save() ; public void update(int id); }Save()方法返回的是int型的 而update方法返回的是void型的;根据上面的猜测是 handler.invoke()是实现 proxyClass.update(2);的,invoke方法中的return方法的是相应的代理方法的返回值,
InvocationHandler中invoke方法中第一个参数proxy貌似只是为了让Proxy类能给自己的InvocationHandler对象的引用调用方法时能传入代理对象proxyClass的引用,来完成proxyClass需要完成的业务。
更多Méthode dimplémentation de proxy dynamique Java en mode proxy相关文章请关注PHP中文网!