初识Java动态代理—JDK代理
代理设计模式的三要素:
- 有原始类
- 额外的方法
- 和原始类实现相同的方法
那么就针对上面三个要求分析和实现动态代理
1.newProxyInstance
newProxyInstance是JDK为我们提供的类,用于创建动态代理对象,参数为
Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
- ClassLoader loader 是类加载器
- Class<?>[] interfaces 是原始实现的接口
- InvocationHandler h 额外方法的实现
那从以上入手
1.获得原始类
原始类很容易获得,通过最简单的new即可例如:
UserService userService =new UserServiceImplNew();
2.和原始类实现相同的接口 interfaces
在上面我们创建出来了userService对象,那么就可以使用class提供的方法获得userService的接口,例如:
userService.getClass().getInterfaces()
3.和原始类实现相同的方法 InvocationHandler
这个将在下面的InvocationHandler中分析
4.类加载器 ClassLoader
- 普通的创建出对象的流程是:
从Java文件到字节码文件,字节码通过ClassLoader(CL)加载到JVM中,从而我们可以把对象创建出来
- 而对于动态代理的方法有所不同
代理对象创建我们并没有new它,或者创建它,那么JVM如何获得代理对象的呢?
JDK提供的动态代理方法有创建字节码的的技术,从interfaces 和InvocationHandler传入的接口信息和方法信息就可以实现出一个代理类
然后用JDK提供的动态代理方法创建出动态字节码
最后使用一个CL加载到JVM中
那么如何实现它呢?
在创建userService时JVM为它的字节码加载设置了一个CL,所以我们可以使用这个CL,也可以称作借用
userService.class.getClassLoader()
2.InvocationHandler
首先实现InvocationHandler接口(ideal自动生成)
该接口实现了一个内部类,我们关注的是invoke方法
InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
};
对于Object invoke(Object proxy, Method method, Object[] args)
- Object proxy 是代理的对象
- Method method 是被代理的对象
- Object[] args 是被代理的对象的参数
前面提到和原始类实现相同的方法,那么怎么实现?
method.invoke(userService,args);
在Object invoke(Object obj, Object... args) 传入想被代理的对象和args即可,它就代表的原始对象,将被执行
现在添加额外功能
详细实现如下
InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDKModle.invoke");
Object ret= method.invoke(userService,args);
return ret;
}
};
3.使用代理对象
UserService userServiceProxy= (UserService) Proxy.newProxyInstance(JDKModle.class.getClassLoader(),userService.getClass().getInterfaces(),handler);
和实现接口一样,只需要代从newProxyInstance得到对象即可
现在把所有代码组装起来
对于下面三个类具体实现,不用关心具体内容,只需要认识方法名字就好
org.User;
org.UserService;
org.UserServiceImplNew;
User
public class User {
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserService
public interface UserService {
public void register(User user);
public void login(String name, String password);
}
UserServiceImplNew
public class UserServiceImplNew implements UserService {
@Override
public void register(User user) {
System.out.println("UserServiceImplNew.register");
}
@Override
public void login(String name, String password) {
System.out.println("UserServiceImplNew.login");
}
}
package org.PoxyModle;
import org.User;
import org.UserService;
import org.UserServiceImplNew;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKModle {
public static void main(String[] args) {
final UserService userService =new UserServiceImplNew();
InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDKModle.invoke");
Object ret= method.invoke(userService,args);
return ret;
}
};
UserService userServiceProxy= (UserService) Proxy.newProxyInstance(JDKModle.class.getClassLoader(),userService.getClass().getInterfaces(),handler);
userServiceProxy.login("SY","1123");
userServiceProxy.register(new User());
}
}
运行如下
3.总结:
JDK动态代理和Spring的动态代理就是一个意思,只不过对JDK封装了,使得更容易使用,了解JDK动态代理对理解AOP编程有好处
newProxyInstance InvocationHandler相互配合才能完成代理操作
初步分析和实现到此为止