博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 基础【19】代理
阅读量:4453 次
发布时间:2019-06-07

本文共 4256 字,大约阅读时间需要 14 分钟。

   Java 代理(Proxy)模式与现实中的代理含义一致,如旅游代理、明星的经纪人。

   在目标对象实现基础上,增加额外的功能操作,由此来扩展目标对象的功能。

   JavaWeb 中最常见的过滤器、Struts 中的拦截器、Spring 中的 AOP...都有代理的应用。

   此篇博客将编写例子描述 Java 底层技术和开源类库Cglib实现代理的方法,并对比各方法的优缺性。

   例子源码:

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 代理有系统的了解。

 

转载于:https://www.cnblogs.com/java-class/p/10455094.html

你可能感兴趣的文章
Angular 资料大集合
查看>>
html基础
查看>>
redis的安装与使用
查看>>
Linux 安装 Djiango
查看>>
统计数组元素的个数和唯一性的函数
查看>>
emacs 利用 auto-complete 自动补齐
查看>>
Spring MVC - 01 HelloWorld
查看>>
request.getSession()几种获取情况之间的差异
查看>>
常用linux命令
查看>>
操作系统线程基本概念
查看>>
爬虫作业
查看>>
Activity、Task、应用和进程
查看>>
mcrypt.h not found. Please reinstall libmcrypt”的解决方法
查看>>
管理 Oracle Cluster Registry(OCR)
查看>>
在阿里云ECS(CentOS6.5)上安装mysql
查看>>
Exception Management Architecture Guide
查看>>
二叉树的所有操作
查看>>
正则表达式的学习笔记
查看>>
HDU1003
查看>>
5年程序员流水帐总结,从开发到产品过渡
查看>>