Java 基础【19】代理
Java 代理(Proxy)模式与现实中的代理含义一致,如旅游代理、明星的经纪人。
在目标对象实现基础上,增加额外的功能操作,由此来扩展目标对象的功能。
JavaWeb 中最常见的过滤器、Struts 中的拦截器、Spring 中的 AOP...都有代理的应用。
此篇博客将编写例子描述 Java 底层技术和开源类库Cglib实现代理的方法,并对比各方法的优缺性。
例子源码:https://github.com/OrsonEx/proxy-demo.git
1.JDK 静态代理
抽象接口:
/**
* 用户服务抽象
*/
public interface UserService { /**
* 用户登录
*
* @param userName 用户名
* @param pwd 密码
* @return 登陆结果
*/
String login(String userName, String pwd);
}
实现该接口:
/**
* 用户服务实现
*
* @author Rambo 2019-03-01
**/
public class UserServiceImpl implements UserService { @Override
public String login(String userName, String pwd) {
Console.log("进行登陆逻辑........."); return "登陆结果";
}
}
编码代理类,实现该接口,代理目标作为私有对象:
/**
* 用户服务代理类
*
* @author Rambo 2019-03-01
**/
public class UserServiceProxy implements UserService {
private UserService userService; UserServiceProxy(UserService userService) {
this.userService = userService;
} @Override
public String login(String userName, String pwd) {
Console.log("登陆前扩展.....");
userService.login(userName, pwd);
Console.log("登陆后扩展.....");
return "登陆结果";
}
}
编写测试类:
@Test
public void testLogin() throws Exception {
UserServiceProxy userServiceProxy = new UserServiceProxy(new UserServiceImpl());
userServiceProxy.login("rambo","111111");
}
最原始实现代理的样子,缺点也很明显,当目标类方法调整后,需要同步维护代理类。且需要单独编码代理类,势必导致冗余。
2.JDK 动态代理(接口代理)
代理核心方法 Proxy.newProxyInstance :
/**
* JDK 生成代理类
* @param loader 当前目标对象使用类加载器
* @param interfaces 目标对象实现的接口的类型
* @param h 事件处理对象,通过反射执行目标对象的方法
* @return 生成的代理类实例
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
代理工厂类:
/**
* 代理工厂类
*
* @author Rambo 2019-03-01
**/
public class JdkProxyFactory { private Object target; public JdkProxyFactory(Object target) {
this.target = target;
} public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Console.log("执行目标前的扩展......");
Object returnValue = method.invoke(target, args);
Console.log("执行目标后的扩展......");
return returnValue;
}
});
}
}
编写测试类:
@Test
public void testGetProxyInstance() throws Exception {
UserService proxyInstance = (UserService) new ProxyFactory(new UserServiceImpl()).getProxyInstance();
proxyInstance.login("rambo", "111111");
}
目标对象需要实现接口,代理对象不用实现目标对象的接口。
需要统一实现 InvocationHandler 接口中 invoke 方法,编码实现目标方法前后的扩展操作。
和静态代理相比:代理对象通过反射动态生成,无需进行编码。目标对象方法进行调整后,代理对象无需做任何调整。
3.Cglib 代理 (子类代理)
当目标对象是个单独的类,没有实现任何接口,是无法使用上述两种代理方法,这时候怎么办?
可以使用 Cglib 代理(需要单独引入 cglib 类库),底层通过一个小而快的字节码处理框架 Asm 来转换字节码并生成新的类。
Cglib 通过自定义目标对象的子类进行目标对象的扩展,且这种扩展进行在 Jvm 运行期。
不局限目标类建模方式(有无继承接口)、运行期增强目标类、底层精致的 asm 字节码框架,使 Cglib 成为许多 AOP 框架生成动态代理的首选。
代理工厂类:
/**
* Cglib 动态代理工厂
*
* @author Rambo 2019-03-01
**/
public class CgbProxyFactory implements MethodInterceptor { private Object target; public CgbProxyFactory(Object target) {
this.target = target;
} public Object getProxyInstance() {
/*
Enhancer类为Cglib库中的字节码增强器,它可以方便对你想要处理的类进行扩展;
将被代理类 target 设置成父类,然后设置当前 intercept 为代理拦截器;
最后执行 enhancer.create() 动态生成一个代理类。
*/
Enhancer en = new Enhancer();
en.setSuperclass(target.getClass());
en.setCallback(this);
return en.create(); } @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Console.log("执行目标前的扩展......");
Object returnValue = method.invoke(target, args);
Console.log("执行目标后的扩展......");
return returnValue;
}
}
编写测试用例:
@Test
public void testGetProxyInstance() throws Exception {
UserService proxyInstance = (UserService) new CgbProxyFactory(new UserServiceImpl()).getProxyInstance();
proxyInstance.login("rambo","111111");
}
JDK InvocationHandler 、Cglib MethodInterceptor 具体实现的细节,如你有兴趣可翻翻源码,这里就不赘述了。
至此代理的几种方式都已描述完毕,希望能帮助你对 java 代理有系统的了解。
Java 基础【19】代理的更多相关文章
- java基础-01代理类
简单的代理类实现案例主实现类:ProxyTestimport java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;im ...
- Java基础-静态代理与动态代理比较
JAVA的静态代理与动态代理比较 静态代理类: 由程序员创建或由特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了.动态代理类: 在程序运行时,运用反射机制动态创建 ...
- Java基础之代理模式
代理模式是常见的设计模式之一,意图在为指定对象提供一种代理以控制对这个对象的访问.Java中的代理分为动态代理和静态代理,动态代理在Java中的应用比较广泛,比如Spring的AOP实现.远程RPC调 ...
- java基础--动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 ...
- Java基础19:Java集合框架梳理
更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...
- java 基础 --- 动态代理和静态代理
问题 : 代理的应用场景是什么 动态代理的底层原理是什么,为什么只能继承接口 概述 代理模式是设计模式的一种,简单地说就是调用代理类的方法实际就是调用真实类的方法.这种模式在AOP (切面编程)中非 ...
- Java基础——动态代理
1.什么是动态代理? 简单的来说,就是本来让我自己做的事,请给别人来做,这个请的人就是代理对象 那么动态代理就是在程序运行过程中产生这个代理对象,而程序运行中产生的对象就是用反射的来生成一个代理. 举 ...
- java基础之代理
代理的定义,代理的应用,代理的特性
- java基础19 导包和“命令行”打jar包
1.导包 1.1.包 java中的包就相当于Windows文件夹 编译格式:javac -d . 类名.java 1.2.包的作用 1.解决了类名重复冲突的问题 2.便于软件版本的 ...
- java基础(19):List、Set
1. List接口 我们掌握了Collection接口的使用后,再来看看Collection接口中的子类,他们都具备那些特性呢? 接下来,我们一起学习Collection中的常用几个子类(List集合 ...
随机推荐
- Python中元类
元类(metaclass) 简单地说,元类就是一个能创建类的类,而类class 是由type创建的,class可以创建对象 type与object的关系详见:python中type和object 1. ...
- C/C++中如何获取数组的长度(宏&模板)
C.C++中没有提供 直接获取数组长度的函数.对于存放字符串的字符数组提供了一个strlen函数获取长度,那么对于其他类型的数组如何获取他们的长度呢?其中一种方法是使 用 sizeof(array) ...
- Spring(二)IOC底层实现原理
IOC原理 将对象创建交给Spring去管理. 实现IOC的两种方式 IOC配置文件的方式 IOC注解的方式 IOC底层实现原理 底层实现使用的技术 1.1 xml配置文件 1.2 dom4j解析xm ...
- css3 webkit-box的用法
webkit-box 1.之前要实现横列的web布局,通常就是float或者display:inline-block; 但是都不能做到真正的流体布局.至少width要自己去算百分比.2.flexibl ...
- 牛客练习赛A 【BFS】
<题目链接> 题目大意: 给出一张图,问你其中 ' # ' 加上那些不能够到达边界的 ' . ' 的点的个数,' # ' 会起阻挡作用. 解题分析: 本题很好做,无非就是将所有能够由边界上 ...
- 8. Rotate String
8. Rotate String Description Given a string and an offset, rotate string by offset. (rotate from lef ...
- Centos6.5部署Rsyslog+LogAnalyzer收集网络及系统日志
1. 介绍 Rsyslog是比syslog功能更强大的日志记录系统,可以将日志输出到文件,数据库和其它程序.可以使用rsyslog替换系统自带的syslog. LogAnalyzer 是一个 sysl ...
- Android应用程序结构
综述:Android应用程序包含哪些部分? assets 可以出发一些随程序打包的文件,应用程序运行时可以动态读取到这些文件的内容. 如果使用到webview加载本地网页的功能,所有网页相关的文件都存 ...
- [COCI2013]DLAKAVAC
[COCI2013]DLAKAVAC 题目大意: 有一个长度为\(m(m\le1500)\)的\(01\)串\(A\),进行\(k(k\le10^{18})\)次操作.一次操作完的串中若\(A_i=1 ...
- 在mongoose中使用正则,参数为变量时的写法
const word = ctx.params.word userModel.find({"name":{$regex: eval(`/${word}/ig`)}}) 如果mong ...