从以下几个方面浅谈一下java的代理机制。如有不足,欢迎留言交流。
类比一:
假如你刚毕业,要租一个房子,有两种方式。一种就是自己去找房源,找房东,这样无疑时间成本是很高的。第二种方式就是找一个房产中介,你只需要提供你的需求和租房的规格和条件。中介就会推荐你心仪的房子。这里的中介就是代理人,房源就是目标对象,你可以直接找房源,也可以通过中介找房源。
类比二:
记者要采访一个儿童。首先需要经过他父母的同意,他的父母就记者提出的问题能进行甄选,那些可以回答,那些问题拒绝回答。这里父母就是代理人,儿童就是目标对象。通过代理可以增强或者控制儿童这个目标对象。
总结: 生活中这样代理的例子还有很多,通过以上的两个简单的例子可以看到,在生活中使用代理往往可以节省时间和成本,使资源能有效的利用。而在程序中使用代理也不例外。以Java的动态代理为例,它的优势就是实现无侵入式的代码扩展,也就是在不修改源码的情况下实现方法的增强,在方法的前后你可以自定义你的实现。在后面的篇幅中会用代码作以说明。
Java的代理类主要有静态代理和动态代理
由程序员创建或者由第三方工具生成,再进行编译;在程序运行之前代理类的.class文件已经存在,这种代理的方式需要代理的对象和目标对象实现一样的接口。
优点: 可以在不修改目标对象的前提下扩展目标对象的功能
缺点:
已更新用户的信息的为例:
1.创建接口
package cn.chen.proxy;
public interface UserDao {
void update();
}
2.目标对象,实现接口
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("更新信息");
}
}
3.创建的代理对象,必须实现接口
public class ProxyUserDao implements UserDao{
private UserDao userDao;
public ProxyUserDao(UserDao userDao){
this.userDao = userDao;
}
/**
* 对原有的方法进行增强
*/
@Override
public void update() {
System.out.println("核对你的信息");
userDao.update();
System.out.println("信息更新成功");
}
}
4.测试
public class ProxyUserTest {
public static void main(String[] args) {
// 目标对象
UserDao userDao = new UserDaoImpl();
// 代理对象
ProxyUserDao proxyUserDao = new ProxyUserDao(userDao);
System.out.println(proxyUserDao.getClass().getName());
proxyUserDao.update();
}
}
运行结果:
cn.chen.proxy.ProxyUserDao
核对你的信息
更新用户
信息更新成功
在程序运行时通过反射机制动态生成
优点:动态代理对象不需要实现与目标对象一致的接口,但要求目标对象必须实现接口,否则不能使用动态代理。
缺点: 使用动态代理的对象必须实现一个或多个接口。在代理类没有接口的情况下,可以使用cglib实现动态代理,达到代理类的无侵入。
静态代理和动态代理的主要区别:
动态代理的实现:
java的动态代理利用了JDK Apl,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。
在jdk中生成代理对象主要涉及的类有:
java.lang.reflect.Proxy 主要方法为:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
这个方法会给与我们来生成一个代理对象,含有三个参数
clasLoader: 类加载器
interface绑定的接口,也就是把代理对象绑定到那些接口下,可以是多个接口
invocationHander 绑定对象的逻辑实现
java.lang.reflect InvocationHander,主要方法为:
Object invoke(Object proxy, Method method, Object[] args)
这个方法也有三个参数
proxy 代理的对象
method 当前的方法
args 运行参数
还是以用户的信息更新为例:
1.创建接口
package cn.chen.proxy;
public interface UserDao {
void update();
}
2.目标对象,实现接口
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("更新信息");
}
}
3.生成代理对象
public class DynamicProxyUser implements InvocationHandler {
// 被代理的对象
private Object object;
public DynamicProxyUser(){}
public DynamicProxyUser(Object object) {
this.object = object;
}
/**
* 处理代理对象的逻辑,所有被代理对象的方法都会在invoke中执行
* @param proxy 代理的对象
* @param method 当前方法
* @param args 方法运行参数
* @return 方法调用结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("核对你的信息");
// 执行目标方法
Object target = method.invoke(object,args);
System.out.println("更新成功");
return target;
}
}
4.测试:
public class DynamicProxyTest {
public static void main(String[] args) {
// 目标对象
UserDao userDao = new UserDaoImpl();
DynamicProxyUser dynamicProxyUser = new DynamicProxyUser(userDao);
ClassLoader loader = userDao.getClass().getClassLoader();
// 调用Proxy的newProxyInstance()方法生成最终的代理对象
UserDao proxy = (UserDao) Proxy.newProxyInstance(loader,new Class[]{UserDao.class},dynamicProxyUser);
System.out.println(proxy.getClass().getName());
proxy.update();
}
}
运行结果:
com.sun.proxy.$Proxy0
核对你的信息
更新信息
更新成功
当然,除了java的代理类型外,比较流行的还有CGLB Javassit,ASM 等。
原文:https://www.cnblogs.com/chentang/p/12444285.html