动态代理
1.动态代理概述
代理模式是Java设计模式中的一种,其特征为代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。
代理类与委托类之间通常存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现业务,而是通过调用委托类对象的相关方法来提供具体业务。
通过反射动态生成代理对象,通过代理对象调用委托类的方法.
作用:代理类会对委托类的方法进行过滤.
在Java中的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和接口可以生成JDK动态代理或动态代理对象。
按照代理的创建时间不同,可以分为两种:
Ø 静态代理:手动创建,再对其编译。在程序运行前,代理类的.class文件就已经存在。
Ø 动态代理:在程序运行时,通过反射机制动态创建而成。
2.动态代理的原理
3.Proxy代理类
Proxy类是Java的java.lang.reflect包下提供的,该类用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。
如果在程序中为一个或多个接口动态地生成实现类,就可以用Proxy类来创建动态代理类;
如果需要为一个或多个接口动态地创建实例,也可以使用Proxy类来创建动态代理实例。
|
|
|
|
|
|
|
|
Ø static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces):
创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口。第一个ClassLoader参数指定生成动态代理类的类加载器。
Ø static Object newProxyInstance(ClassLoaderloader, Class<?>[] interfaces, InvocationHandler h):
直接创建一个动态代理对象,该代理对象的实现类实现了interfaces指定的系列接口,执行代理对象的每个方法时都会被替换执行InvocationHandler对象的invoke()方法。
4.InvocationHandler
InvocationHandler接口提供了invoke()方法,用于替换代理对象的每一个方法。
真实业务类可以通过代理类对象调用InvocationHandler接口提供的invoke()方法,来替代调用委托类的真实方法。
invoke()方法:通过代理对象去执行委托类的方法 , 即代理对象通过该方法去执行委托类的方法以下是InvocationHandler的API内容:
|
Ø Object invoke(Object proxy, Method method, Object[] args):
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
² 参数proxy:表示代理类对象,也就是Proxy.newProxyInstance()方法返回的对象,通常用不上。
² 参数method:表示当前被调用方法的反射对象,
² 参数args:表示调用目标方法时传入的实参。
5.实现动态代理
* newProxyInstance()
invocationHandler接口:
* invoke(proxy对象,Method,对应方法的实参)
利用Java提供的Proxy类和InvocationHandler接口来生成动态代理类或动态代理对象,具体实现步骤如下:
1.定义一个业务接口,该接口提供具体业务方法的定义。
public interface Person {
void sayMe();
void sayHello(String name);
}
2.定义一个InvocationHandler接口的实现类,并重写invoke()方法。
public class MyInvocationHandler implements InvocationHandler {
/**
* 执行动态代理对象的所有方法时,都会被替换成执行下面的invoke()方法.
* * 参数proxy:代表动态代理对象.
* * 参数method:代表正在执行的方法.
* * 参数args:代表调用目标方法时传入的实参.
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("---正在执行的方法: "+method);
if(args == null){
System.out.println("当前调用的方法没有参数.");
}else{
System.out.println("当前调用的方法需要传入的实参为:");
for (Object val : args) {
System.out.println(val);
}
}
return null;
}
}
3. 编写一个用于测试动态代理的测试类。
public class ProxyTest {
public static void main(String[] args) {
// 创建一个InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler();
// 通过Proxy类使用指定的InvocationHandler来生成动态代理对象
Person p = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler);
// 调用动态代理对象的业务方法
p.sayMe();
p.sayHello("张无忌");
}
}
6、动态代理的作用
阻止调用对应委托类的方法.
修改委托类方法的返回值.
通过Java提供的Proxy类和InvocationHandler接口生成的动态代理类,可以阻止调用委托类的方法、过滤参数及修改对应方法的返回值等作用。
实现业务接口方法的实现类即委托类,具体操作如下:
1、创建一个实现类,实现Person接口,并重写业务方法。
public class Fanbingbing implements Person {
@Override
public void sayMe() {
System.out.println("我真的是范冰冰哦!");
}
@Override
public String sayHello(String name) {
System.out.println("你好:"+name+",我等你很久了...");
return "我终于见到范冰冰啦!";
}
}
2、编写一个用于测试动态代理的测试类。
public class FanbingbingTest {
public static void main(String[] args) {
Person p = (Person) Proxy.newProxyInstance(
Person.class.getClassLoader(),
Fanbingbing.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// 通过method的getName()方法获取业务方法名,进行阻止.
if (method.getName().equals("sayMe")) {
System.out.println("你想多了,哪那么容易见到啊!");
return null;
}
// 通过args获取实参,进行修改
if(method.getName().equals("sayHello")){
String name = (String)args[0];
method.invoke(Class.forName("app.java.proxy.Fanbingbing").newInstance(), "某局长");
}
// 修改返回值
if(method.getName().equals("sayHello")){
return "都是假的!";
}
return null;
}
});
p.sayMe();
p.sayHello("张无忌");
}
}
Star:
package app.java.proxy;
public interface Star {
public void song(String name);
public String movie();
}
Fbb:
package app.java.proxy;
public class Fbb implements Star {
public void song(String name) {
System.out.println(name+" song........");
}
public String movie() {
System.out.println("movie........");
return "武媚娘传奇,禁播了!!!";
}
}
ProxyTest:
package app.java.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
/**
* Proxy类的newProxyInstance(ClassLoader,Class[])方法:
* * 获取对应委托类的代理对象.
* * 参数一:指定对应委托类的类加载器.
* * 参数二:指定委托类的Class
* * 参数三:InvocationHandler的实例(重写invoke)
*
* 动态代理的作用:
* * 不需要得到对应委托类的对象.
* * 通过代理类对象,对委托类的方法进行过滤(修改)等.
*/
Star fbb = (Star)Proxy.newProxyInstance(Star.class.getClassLoader(), Fbb.class.getInterfaces(), new InvocationHandler() {
/**
* invoke(Object proxy, Method method, Object[] args)
* * 该方法的作用:调用对应的委托类的方法.
* * 参数一:返回的是代理类对象.
* * 参数二:返回的是对应委托类方法的Method类型对象.
* * 参数三:返回的是对应委托类方法接收的实参.
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 可以获取到对应委托类方法的参数.
/*String name = (String)args[0];
if(name.equals("zhangwuji")){
method.invoke(new Fbb(), "zhouzhiruo");
}*/
// 阻止调用对应委托类的方法
/*String methodName = method.getName();
if(methodName.equals("movie")){
System.out.println("范冰冰最近太累了,不能拍电影,改唱歌了!");
}*/
// 修改委托类方法的返回值
String methodName = method.getName();
if(methodName.equals("movie")){
return "武媚娘传奇,重播了!!!";
}
return null;
}
});
// fbb.song("zhangwuji");
String value = fbb.movie();
System.out.println(value);
}
}
ProxyTest2:
package app.java.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest2 {
public static void main(String[] args) {
Star star = (Star)Proxy.newProxyInstance(Star.class.getClassLoader(), Fbb.class.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(new Fbb(), args);
}
});
System.out.println(star);
star.movie();
}
}