一.创建代理的三要素:
- 原始对象
- 额外功能
- 代理对象和原始对象实现相同的接口
打个比方,我去卖房子,然后我要带客户去看房子;可是有一天,我不想每天都带那么多的客户去看房子,我该怎么办呢?找中介.让中介代替我,领着客户去看房子.那么中介需要伪装成是房东(此时就要重写原始对象中的方法).
二.JDK动态代理:
Proxy.newProxyInstance(classloader,interfaces,invocationHandler)
2.1 invocationHandler介绍:
2.1.1 MethodInterceptor拦截器回顾:
我们在学习spring动态代理之MethodInterceptor拦截器的时候,需要实现MethodInterceptor接口,此时重写了接口中的invoke方法,invoke参数中有一个MethodInvocation,它此时代表额外功能增加的那个原始方法,代码如下:
public class Arroud implements MethodInterceptor {
/**
* spring动态代理之MethodInterceptor拦截器
* @param methodInvocation :额外功能增加的那个原始方法,如:register(),login()
* @return: 因为每个方法的返回值都不一样,所以需要object类来接受
* @throws Throwable
*/
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("额外功能----");
//表示:该原始方法执行了,如register,login方法
Object proceed = methodInvocation.proceed();
System.out.println("方法的返回值:object="+proceed);
return proceed;
}
}
我们会发现,这个methodInvocation是被spring进行封装了的,但是我们的JDK的代理还是原生的.
2.1.2 InvocationHandler介绍和演示:
invocationHandler是一个接口.我们需要重写invoke方法,从而来增加额外的功能
/**
* 2.额外功能
*
*
*/
final InvocationHandler invocationHandler=new InvocationHandler() {
/**
* 为什么是method.invoke? 因为动态代理. 省去了service.register,service.login()
*
* @param proxy 代理对象
* @param method 原始对象的原始方法
* @param args 原始方法的参数
* @return 原始方法的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//2.1 新增额外功能
System.out.println("jdk proxy...");
//2.2 执行原始对象的原始方法
Object invoke = method.invoke(userService, args);
return invoke;
}
};
语法糖: jdk1.8之后,我们可以省略掉上面的final修饰符
三. interfaces介绍:
代理创建3要素的第三条,代理对象和原始对象需要实现相同的接口,这里的interfaces就是实现的接口.
此时,我们怎么获取到这个接口呢?通过getClass().getInterfaces()可以获取到类的所有接口定义.
四. classloader介绍:
4.1 类加载器怎么获取呢?
(1).我们知道,一个user.java文件,通过编译成user.class的字节码文件,这里每个类的class文件,自动会分配与之对应的classloader类加载器;
(2).类加载器会把user.class字节码文件放入到JVM虚拟机中;
(3).jvm虚拟机如何去创建一个user对象呢?此时肯定需要拿到user的class对象才能去创建user对象.此时也是通过类加载器去生成Class对象.
此时,问题来了,我现在是动态代理呀,我拿不到具体的.java文件,我也没有具体的.class文件呀,顺其自然的,我也就没有对应的类加载器呀,我该怎么办?
答: 去借一个
五.最终的JDK动态代理代码如下:
package com.baizhiedu.jdl;
import com.baizhiedu.proxy.User;
import com.baizhiedu.proxy.UserService;
import com.baizhiedu.proxy.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理
*/
public class TestJdkProxy {
public static void main(String[] args) {
//1.创建原始对象UserService
final UserService userService = new UserServiceImpl();
/**
* 2.额外功能
*
*
*/
final InvocationHandler invocationHandler=new InvocationHandler() {
/**
* 为什么是method.invoke? 因为动态代理. 省去了service.register,service.login()
*
* @param proxy 代理对象
* @param method 原始对象的原始方法
* @param args 原始方法的参数
* @return 原始方法的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//2.1 新增额外功能
System.out.println("jdk proxy...");
//2.2 执行原始对象的原始方法
Object invoke = method.invoke(userService, args);
return invoke;
}
};
/**
* 3.代理对象和原始对象实现相同的接口 interfaces:原始对象所实现的接口
* 先借用userService的classLoader TestJdkProxy也可以
*/
UserService service = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
service.login(new User());
service.register("Nisy",20);
}
}
5.1 运行结果:
jdk proxy...
登录功能的核心代码...
jdk proxy...
注册功能的核心代码...