网站首页 > 精选教程 正文
Java中的动态代理
动态代理是动态地创建代理并动态地处理对所代理方法的调用。
实现动态代理需要实现InvocationHandler接口,实现其invoke(object, method, args[])函数,传递的是一个代理实例(Proxy类库的$Proxy0)、方法和参数。
Java动态代理的创建
动态代理对象是用静态方法Proxy.newProxyInstance()方法创建的:
- 第一个参数是希望代理的接口的类加载器,
- 第二个参数是希望该代理实现的接口列表(Class对象数组),
- 第三个参数是InvocationHandler接口的一个实现(Proxy.newProxyInstance()返回值可以强制转换成接口,不能强制转换成实现类,因此Java动态代理,只能代理接口,不能代理类【只能代理接口的意思是,创建代理后,只能通过接口的方式来调用代理的实现。】)。
动态代理代理的方法都会经过第三个参数的对象所实现的invoke方法来进行代理调用,因此通常会向调用处理器传递一个“实际对象”的引用(如下面的readObject对象),从而使得调用处理器可以将请求转发。如下图:
上图中:
- 代理类实例proxy的类名是:$Proxy0
- proxy中的属性有:m1, m0, m3, m4, m2
- proxy中的方法有:equals, toString, hashCode, doSomething, somethingElse
- proxy的父类是:class java.lang.reflect.Proxy
- proxy实现的接口是:opensource.Test$Interface
动态代理的作用
动态代理主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。还有一个有趣的作用是可以用作远程调用,比如现在有Java接口,这个接口的实现部署在其它服务器上,在编写客户端代码的时候,没办法直接调用接口方法,因为接口是不能直接生成对象的,这个时候就可以考虑代理模式(动态代理)了,通过Proxy.newProxyInstance代理一个该接口对应的InvocationHandler对象,然后在InvocationHandler的invoke方法内封装通讯细节就可以了。具体的应用,最经典的当然是Java标准库的RMI,其它比如hessian,各种webservice框架中的远程调用,大致都是这么实现的。见下面的例子:
package com.proxy.test;
public interface UserLogin {
public void login(String userName);
}
package com.proxy.test;
public class UserLoginImpl implements UserLogin {
public void login(String userName) {
System.out.println("欢迎 " + userName + " 登录系统");
}
}
package com.proxy.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyHandler implements InvocationHandler {
private Object obj;
public MyHandler(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeLogin(); // 登录前处理,更具自己需要来写
Object result = method.invoke(obj, args); // 调用真正的方法
afterLogin(); // 登录后处理,更具自己需要来写
return result;
}
public void beforeLogin() {
System.out.println("登录前处理");
}
public void afterLogin() {
System.out.println("登录后处理");
}
}
package com.proxy.test;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
UserLoginImpl user = new UserLoginImpl(); // 得到实例对象
MyHandler handler = new MyHandler(user); // 将对象传入自己的处理器中
UserLogin proxy = (UserLogin) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass()
.getInterfaces(), handler); // 得到代理对象
proxy.login("张三"); // 代理调用login方法
}
}
Spring AOP动态代理
Spring AOP通过代理模式实现,目前支持两种代理:
- JDK动态代理。
- CGLIB代理来创建AOP代理。
Spring建议优先使用JDK动态代理。
JDK动态代理
使用java.lang.reflect.Proxy动态代理实现,即提取目标对象的接口,然后对接口创建AOP代理。
CGLIB代理
CGLIB代理不仅能进行接口代理,也能进行类代理。
CGLIB代理需要注意以下问题:不能代理final方法,因为final方法不能被覆盖(CGLIB通过生成子类来创建代理);会产生两次构造器调用,第一次是目标类的构造器调用,第二次是CGLIB生成的代理类的构造器调用(CGLIB要求被代理的类要有默认的构造函数,因为子类实例化时会隐式调用super());如果需要CGLIB代理方法,请确保两次构造器调用不影响应用。
Spring AOP默认首先使用JDK动态代理来代理目标对象,如果目标对象没有实现任何接口将使用CGLIB代理,如果需要强制使用CGLIB代理,请使用如下方式指定:
- 对于Schema风格配置切面使用如下方式来指定使用CGLIB代理:<aop:config proxy-target-class="true"></aop:config>
- 而如果使用@AspectJ风格使用如下方式来指定使用CGLIB代理:<aop:aspectj-autoproxy proxy-target-class="true"/>
原创文章多多支持!欢迎关注!
好书推荐!Java界公认的权威书籍!坚持读完,轻松拿下阿里巴巴offer!下方链接直接京东自营购买!
猜你喜欢
- 2024-11-19 阿里高频面试题汇总
- 2024-11-19 Java 类加载:性能影响
- 2024-11-19 Dubbo的使用及原理分析
- 2024-11-19 Java常用的包库及快捷键
- 2024-11-19 JAVA动态代理的作用是什么?
- 2024-11-19 2022 Java 企业面试题汇总
- 2024-11-19 SpringCloud远程服务调用的方式RPC和HTTP
- 2024-11-19 Android APP漏洞之战(7)——信息泄露漏洞详解
- 2024-11-19 微服务的那些事(三),微服务的远程调用方式。RPC和HTTP
- 2024-11-19 C#宿舍管理系统
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)