我想在网上查了一些有关 Java 动态代理相关的技术资料,发现讲的都是一些理论或者源码,没有太多实际的应用举例,让人看的云里雾里、似懂非懂。索性我就自己总结一下,方便后续在使用时进行快速查阅。
Java 动态代理技术其实是 AOP 编程思想的实现。AOP 编程思想可以简单的理解为:在不改变原有业务代码情况下,实现对原有业务功能的修改或扩展。
AOP 编程思想在我们的实际开发中经常使用,比如你开发了一个网站系统,某些功能需要有权限才能使用,你肯定不想在每个具体的方法上进行硬编码实现权限验证,这样很不好统一维护,你会编写一个权限过滤器,对用户的请求进行拦截,验证用户权限。这里的权限过滤器其实就是 AOP 编程思想的一个体现,在不改变原有业务功能代码的情况下,实现对原有业务功能的权限验证扩展。
Java 动态代理技术 AOP 编程思想的实现方式,本质上就是利用反射技术,为实现了【具体接口】的实现类对象,创建实现了【具体接口】的代理对象,通过对代理对象的 invoke 方法进行代码修改,从而在不改变原有实现类代码的前提下,对原有实现类实例化后的对象的相关方法进行功能修改或者扩展。
从上面的描述可以发现:要实现 Java 动态代理技术,首先必须要有一个接口,以及该接口的实现类。下面我们还是举一个简单的例子来详细介绍 Java 动态代理技术吧。
// 定义一个接口
public interface PersonInterface {
//上午
void Morning();
//下午
void Afternoon();
//傍晚
void Evening();
//夜里
void Night();
}
// 定义 Person 类,实现了 PersonInterface 接口中的方法
public class Person implements PersonInterface {
@Override
public void Morning() {
System.out.println("上午:读书学习...");
}
@Override
public void Afternoon() {
System.out.println("下午:锻炼身体...");
}
@Override
public void Evening() {
System.out.println("傍晚:听歌娱乐...");
}
@Override
public void Night() {
System.out.println("夜里:早点睡觉...");
}
}
现在我们要实现目标是:在不改变 Person 类中任何源代码的情况下,对 Person 类实例化后的对象中 Morning、Afternoon、Evening 这 3 个方法,进行功能增强或者修改,调用这 3 个方法打印的内容是修改后的内容,不是原有内容。
注意:要求必须使用 Person 类进行实例化对象,然后调用 Morning、Afternoon、Evening 这 3 个方法。
这就导致我们无论是采用一个新的类,去实现 PersonInterface 接口,重新实现 Morning、Afternoon、Evening 这 3 个方法,还是采用一个新的类,继承 Person 去重写 Morning、Afternoon、Evening 这 3 个方法,都是不可行的。因为最终我们实例化 Person 对象后,打印的还是 Person 中这 3 个方法的原有内容。
这里只能采用 Java 动态代理技术来实现,具体代码如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//实例化一个 Person 对象 wolfer
Person wolfer = new Person();
/*
基于 wolfer 对象和 PersonInterface 接口,创建动态代理对象
*/
//第一种方式:采用匿名内部类实现
PersonInterface wolferProxy = (PersonInterface) Proxy.newProxyInstance(
//wolfer 对象的类加载器,其实就是 Person 类的加载器
wolfer.getClass().getClassLoader(),
//wolfer 对象所实现的接口的字节码,其实就是 Person 类所实现的接口的字节码
wolfer.getClass().getInterfaces(),
//动态代理的具体实现(匿名内部类实现方式)
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
try {
if ("Morning".equals(method.getName())) {
//如果是 wolfer 对象的 Morning 方法
//给 wolfer 对象的原有 Morning 方法代码前,增加一行代码
System.out.println("上午:睡到自然醒,然后起床...");
//调用 Morning 的原有方法
return method.invoke(wolfer, args);
} else if ("Afternoon".equals(method.getName())) {
//调用 Afternoon 的原有方法,获取返回值
Object obj = method.invoke(wolfer, args);
//如果是 wolfer 对象的 Afternoon 方法
//给 wolfer 对象的原有 Afternoon 方法代码后,增加一行代码
System.out.println("下午:去吃个大餐,补充能量...");
return obj;
} else if ("Evening".equals(method.getName())) {
//如果是 wolfer 对象的 Evening 方法
//直接改变了 Evening 原有方法的实现代码
System.out.println("傍晚:灯红酒绿,纸醉金迷...");
//由于 Evening 方法不需要返回值,因此这里返回 null 即可
return null;
} else {
//其它方法不进行改变和扩展,直接调用原有方法
return method.invoke(wolfer, args);
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
});
//第二种实现方式:
//由于动态代理的第 3 个参数 InvocationHandler 是仅有一个方法的接口,
//因此可以简化为 Lambda 表达式的编写方式
PersonInterface wolferProxy = (PersonInterface) Proxy.newProxyInstance(
wolfer.getClass().getClassLoader(),
wolfer.getClass().getInterfaces(),
(proxy, method, proxyArgs) -> {
try {
if ("Morning".equals(method.getName())) {
System.out.println("上午:睡到自然醒,然后起床...");
return method.invoke(wolfer, proxyArgs);
} else if ("Afternoon".equals(method.getName())) {
Object obj = method.invoke(wolfer, proxyArgs);
System.out.println("下午:去吃个大餐,补充能量...");
return obj;
} else if ("Evening".equals(method.getName())) {
System.out.println("傍晚:灯红酒绿,纸醉金迷...");
return null;
} else {
return method.invoke(wolfer, proxyArgs);
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
);
//上面两种实现方式,只保留一种即可
//调用 wolfer 的动态代理对象的 Morning 方法,发现:
//相比 Person 类的原有 Morning 方法,前面增加了一句打印
wolferProxy.Morning();
//调用 wolfer 的动态代理对象的 Afternoon 方法,发现:
//相比 Person 类的原有 Afternoon 方法,发现后面增加了一句打印
wolferProxy.Afternoon();
//调用 wolfer 的动态代理对象的 Evening 方法,发现:
//相比 Person 类的原有 Evening 方法,打印的内容被彻底改变了
wolferProxy.Evening();
//调用 wolfer 的动态代理对象的 Night 方法
//由于动态代理没有对其修改和扩展,因此打印内容跟 Person 类原有的 Night 方法相同
wolferProxy.Night();
}
}
/*
打印内容如下所示:
上午:睡到自然醒,然后起床...
上午:读书学习...
下午:锻炼身体...
下午:去吃个大餐,补充能量...
傍晚:灯红酒绿,纸醉金迷...
夜里:早点睡觉...
*/
Ok,通过以上例子,应该能够快速理解并掌握 Java 动态代理技术了。
实际应用场景是:如果你引用了第三方的 jar 包,如果你感觉它的某些类的方法不太满足自身的需求,想要改变或增强的话,而这些类恰好也实现了某些接口,此时就可以使用 Java 动态代理技术就行修改或增强,来满足自身业务的需要。另外在 Java 的各种框架中,比如 Spring 相关框架也广泛使用 Java 动态代理技术。
希望以上内容对大家有用。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/191159.html