动态代理 (原理)
1.动态代理原理及代码实现
- 动态代理非常的灵活,可以为任意的接口实现类对象做代理。
- 动态代理可以为被代理对象的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强,
- 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。
- 动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。
- 动态代理同时也提高了开发效率。
- 缺点:只能针对接口的实现类做代理对象,普通类是不能做代理对象的。
java.lang.reflect.InvocationHandler接口 是代理实例的调用处理程序 实现的接口。用来生产代理人对象的动态代理接口。
可以把被代理对象传递到InvocationHandlerImpl类中,让InvocationHandlerImpl生产被代理对象的代理人对象。
InvocationHandler接口中的方法:
// 在代理实例上处理方法调用并返回结果。
// 作用:使用invoke方法对被代理人的方法进行拦截,让部分方法可以运行,部分方法不能运行
Object invoke(Object proxy, Method method, Object[] args)
参数:
Object proxy // 内部产生的代理人对象,不用管
Method method // invoke方法对传递被代理对象的方法进行拦截,方法内部使用反射技术获取到拦截到的方法
Object[] args // 拦截到方法的参数
返回值:
Object // 就是拦截到的方法的返回值
想要实现动态代理:使用Proxy类(java.lang.reflect.Proxy)生成代理人对象
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
Proxy类中的静态方法:
// 返回一个指定接口的代理类对象实例,该接口可以将方法调用指派到指定的调用处理程序。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数:
ClassLoader loader // 传递类加载器
Class<?>[] interfaces // 传递被代理对象实现的所有接口
InvocationHandler h // 生成代理人的接口,传递InvocationHandler接口的实现类对象
返回值:
Object // 返回的就是创建好的代理人对象
InvocationHandler接口的实现类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class InvocationHandlerImpl implements InvocationHandler{
//在实现类中定义一个Star类型的变量,用于接收被代理人的对象
private Star star;
//使用构造方法,把明星传递到类中,给Star变量赋值
public InvocationHandlerImpl(Star star) {
this.star = star;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取到方法的名称
String methodName = method.getName();
//对方法的名称进行判断
if("chifan".equals(methodName)){
throw new RuntimeException("不和你吃饭!");
}
if("wanyouxi".equals(methodName)){
throw new RuntimeException("不和你玩游戏!");
}
//其他的方法,使用Method对象调用invoke方法运行方法
Object v = method.invoke(star, args);
return v;
}
}
测试类:
import java.lang.reflect.Proxy;
/*
动态代理:
创建代理人对象,对明星进行代理,对明星的方法进行拦截
调用明星的changge,tiaowu,yandianying方法放行==>可以运行
调用明星的chifan,wanyouxi方法拦截==>不让方法运行
*/
public class Demo01Proxy {
public static void main(String[] args) {
CaiXuKun cxk = new CaiXuKun();
//使用Proxy类中的静态方法newProxyInstance获取代理人对象
Star cxkProxy = (Star)Proxy.newProxyInstance(CaiXuKun.class.getClassLoader(),
CaiXuKun.class.getInterfaces(), new InvocationHandlerImpl(cxk));
cxkProxy.changge();
cxkProxy.tiaowu();
cxkProxy.chifan(); //RuntimeException: 不和你吃饭!
String s = cxkProxy.yandianying(100);
System.out.println(s);
}
}
2.动态代理综合案例
代码实现:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/*
需求:
使用动态代理模拟unmodifiableList方法,对List接口进行代理
调用List接口的方法会被拦截
如果使用的size,get方法,没有对集合进行修改,则允许执行
如果使用的add,remove,set方法,对集合进行了修改,则抛出运行时异常
分析:
1.定义一个代理方法proxyList
参数:传递List集合
返回值:被代理之后的List集合
2.方法内部可以使用Proxy类中的方法实现动态代理
*/
@SuppressWarnings("all") //注解的作用是抑制警告,不让警告出现
public class Demo02Proxy {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
List<String> proxyList = proxyList(list);
System.out.println(proxyList.size());//3
System.out.println(proxyList.get(2));//c
proxyList.add("d");//UnsupportedOperationException: add no run!
proxyList.remove(1);//UnsupportedOperationException: remove no run!
proxyList.set(1,"www");//UnsupportedOperationException: set no run!
}
//1.定义一个代理方法proxyList 参数:传递List集合 返回值:被代理之后的List集合
public static List<String> proxyList(List<String> list){
//2.方法内部可以使用Proxy类中的方法实现动态代理
List<String> listProxy = (List<String>)Proxy.newProxyInstance(
list.getClass().getClassLoader(), list.getClass().getInterfaces(),
new InvocationHandler() {
//invoke方法对List集合的方法进行拦截,让部分方法可以运行,让部分方法不能运行,抛出异常
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取拦截到的方法的名称
String methodName = method.getName();
//如果使用的add,remove,set方法,对集合进行了修改,则抛出运行时异常
if("add".equals(methodName)){
throw new UnsupportedOperationException("add no run!");
}
if("remove".equals(methodName)){
throw new UnsupportedOperationException("remove no run!");
}
if("set".equals(methodName)){
throw new UnsupportedOperationException("set no run!");
}
//如果使用的size,get方法,没有对集合进行修改,则允许执行
Object v = method.invoke(list, args);
return v;
}
});
return listProxy;
}
}
动态代理案例流程图
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112026.html