动态:就是程序在运行时创建的对象(不在内存中)
代理:对目标对象包装(增强增加功能)
动态代理的作用:在可以不修改原方法的情况下,对原对象接口中的方法进行增强
{
代理对象:增强对象
目标对象:要被增强的对象
目标方法:要被增强的方法
}
{
动态代理的使用条件:
1要明确目标对象
2代理对象和目标对象必须有相同的方法
{
目标对象必须有接口
因为代理对象要实现相同的接口
}
}
-------------------------------------------------
假设:有一个IUser的接口{void 增删改查功能};有一个接口实现类User{实现增删改查的功能}
IUser user=new User()
发生情况:
如果,知道了User实现类在哪,并且可以进行修改。完全可以利用继承,用继承User并实现方法,当然也可以使用动态代理
弊端:不知道父类是谁{
例如request。当使用时,request是Tomcat创建,我们用来使用的。
但是当我们对request对象的方法进行增强时,我们不知道request实现的类。注:HttpServletRequest是接口
所以不能使用继承了,如果知道父类,那么推荐还是继承。
}
如何对request进行增强:使用动态代理。
jdk提供的动态代理的类:Proxy类
主要方法摘要:
static Object | newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
参数:
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
h
- 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
--------------------------------------------------------------------------------------------
//参数1:类加载器(可以将一切的.class文件加载到内存中运行){
类加载器只有一个,所以这里参数要拿到类加载器只要是个 类.class.getClassLoader() 当前项目下的类就可以。
可以将代理对象加载到内存,此时它没有方法。
}
//参数2:指定代理对象要继承哪个接口 因为要和目标对象有一样的方法{
只有方法,没有实现。此时有了相同 的方法。
}
//参数3:增强业务类(接口的实现),InvocationHandler是个接口,里面要放个实现invoke()。
IUser user = new User();
IUser userProxy=(IUser)Proxy.newProxyInstance(Demo.class.getClassLoader(), new Class[]{IUser.class}, new InvocationHandler() {
//invoke相当于代理对象的底层方法
//invoke的调用时机:代理对象调用任何方法 invoke方法都会执行,invoke里面的内容就是调用方法的内部实现
// method:就是方法对象(目标对象的方法对象)invoke反射出的方法。
// args:这个方法在执行过程中需要的参数(目标对象的方法参数)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1 之前增强
System.out.println(增强前);------------------》增强
// 2 调用目标对象的原方法
// 目标对象
// 目标对象的方法名
method.invoke(user,args);------------》反射获得原方法
// 3 之后增强
System.out.println(增强后);--------------》增强
//谁调用返回给谁。(调用目标对象之后 的返回值)
return null;
}
});
//代理对象调用方法
String value=userProxy.方法("参数");
此外,proxy:是代理对象,一般不用。
代理对象不具有目标对象的功能
代理对象可以调用目标对象的功能,只调用接口中的方法
代理对象可以增强功能