小工具      在线工具  汉语词典  css  js  c++  java

Java代理(jdk静态代理、动态代理和cglib动态代理)

Java 额外说明

收录于:42天前

代理模式是一种常用的Java设计模式。其特点是代理类和委托类具有相同的接口。代理类主要负责为委托类预处理消息、过滤消息、将消息转发给委托类以及事后处理消息。代理类和委托类之间通常存在关联。代理类的对象与委托类的对象相关联。代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法来实现服务。提供特定服务。​

1.JDK动态代理

1.业务接口(必须有)

package com.sww.proxy;

public interface HelloWorldJDKProxy {

    void helloWorld();
}

2.业务变现

package com.sww.proxy;

/**
 * JDK 动态代理测试
 *
 * @author TF12778 2019/1/28 09:49
 */
public class HelloWorldJDKProxyImpl implements HelloWorldJDKProxy {

    public void helloWorld() {
        System.out.println("Hello World JDK Proxy!");
    }
}

3.代理类

package com.sww.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK动态代理
 *
 * @author TF12778 2019/1/28 09:52
 */
public class JDKInvocationHandler implements InvocationHandler {

    private Object target;

    public JDKInvocationHandler(Object target){
        this.target = target;
    }

    /**
     * 创建代理实例
     * @return
     * @throws Throwable
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread()
                .getContextClassLoader(), this.target.getClass()
                .getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method:" + method.getName() + " is invoked!");
        return method.invoke(target, args);
    }
}

4.JDK动态代理测试

package com.sww.proxy;

/**
 * JAVA JDK动态代理
 *
 * 代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强。加入一些非业务性代码,比如事务、日志、报警发邮件等操作。
 *
 * @author TF12778 2019/1/28 09:44
 */
public class ProxyController {

    public static void main(String[] atgs){

        /**
         * JDK 动态代理
         */
        HelloWorldJDKProxy jdkProxy = new HelloWorldJDKProxyImpl();
        JDKInvocationHandler handle = new JDKInvocationHandler(jdkProxy);

        // 根据目标生成代理对象
        HelloWorldJDKProxy proxy = (HelloWorldJDKProxy)handle.getProxy();
        proxy.helloWorld();

    }
}

检测结果:

method:helloWorld is invoked!
Hello World JDK Proxy!

2.CGLib动态代理

1.业务实现(不需要业务接口类)

package com.sww.proxy;

/**
 * 业务类
 * 没有实现接口
 * 如果类是final的,则没法生成代理对象,报错。
 * 如果方法是final的,代理无效
 *
 *
 * @author TF12778 2019/1/28 10:31
 */
public class HelloWorldCGlibImpl {

    public void showCGLibMsg() {
        System.out.println("CGLibMsg Test Success");
    }
}

2.代理类

package com.sww.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 使用Cglib动态代理
 *
 * @author TF12778 2019/1/28 10:35
 */
public class CGlibMethodInterceptor implements MethodInterceptor
{

    private Object target;

    public Object getInstance(Object target) {
        this.target = target;

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        //  设置回掉方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    /**
     *
     * @param o
     * @param method
     * @param objects
     * @param 实现MethodInterceptor接口要重写的方法
     * @return
     * @throws 回调方法
     */
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        System.out.println("事物开始。。。。。。");
        Object result = methodProxy.invokeSuper(obj, args);
        System.out.println("事物结束。。。。。。");
        return result;
    }
}

3. 测试

package com.sww.proxy;

/**
 * JAVA JDK动态代理
 *
 * 代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强。加入一些非业务性代码,比如事务、日志、报警发邮件等操作。
 *
 * @author TF12778 2019/1/28 09:44
 */
public class ProxyController {

    public static void main(String[] atgs){

    /**
     * CGLib 动态代理
     */
    CGlibMethodInterceptor cglibProxy = new CGlibMethodInterceptor();
    HelloWorldCGlibImpl  HelloCGlibImpl = (HelloWorldCGlibImpl)cglibProxy.getInstance(new HelloWorldCGlibImpl());
        HelloCGlibImpl.showCGLibMsg();

    }
}

检测结果:

事物开始。。。。。。
CGLibMsg Test Success
事物结束。。。。。。

三、总结

一、原理

jdk静态代理的实现比较简单。一般情况下,直接代理对象直接包装代理对象。

jdk动态代理是接口代理。代理类A需要实现业务接口,业务代理类B需要实现InitationHandler接口。

jdk动态代理会生成一个jdk代理类,该类继承Proxy类,并根据代理对象实现业务接口。这个类的字节码会被传入的ClassLoader加载,并创建一个jdk代理对象实例。

当jdk代理对象实例创建时,业务代理对象实例会被赋值给Proxy类。 jdk代理对象实例还有一个业务代理对象实例。同时jdk代理对象实例通过反射根据代理类的业务方法创建对应的业务方法。方法对象m(可能有多个)。当jdk代理对象实例调用业务方法时,如proxy.addUser(); this会首先将对应的m对象作为参数传递给invoke()方法(也就是invoke方法的第二个参数),然后调用jdk代理对象实例。 Invoke()回调方法,invoke方法中通过反射调用代理对象的方法,即result = method.invoke(target, args);。

cglib动态代理是一个继承代理,通过ASM字节码框架修改字节码生成新的子类,重写和增强方法的功能。

2. 优点和缺点

jdk静态代理类只能服务一个代理类。如果需要代理的类较多,就会生成过多的代理类。 jdk静态代理在编译时生成class文件,运行时不需要生成。可以直接使用,效率高。

jdk动态代理必须实现接口,通过反射动态代理方法,消耗系统性能。但不需要生成过多的代理类,避免了重复代码的生成,系统更加灵活。

cglib动态代理不需要实现接口,通过生成子类字节码来实现,比反射速度更快,并且没有性能问题。但是,由于cglib会继承代理类,需要重写代理方法,所以代理类不能是final类,代理方法也不能是final。

因此cglib的应用更为广泛。

参考: https://www.cnblogs.com/fillPv/p/5939277.html

. . .

相关推荐

额外说明

Java使用POI导出Excel

目录 一、前景 二、概念 2.1. 简介 2.2.Excel版本和相关对象 2.3.WorkBook 2.4.POI依赖 三、POI - 写 3.1.代码示例 3.2. 性能对比 3.3. 测试rowAccessWindowSize 3.4. 导出Exc

额外说明

Docker安装SQL Server教程

本文教你如何快速通过Docker安装SQL Server 前置条件:服务器内存需要于2GB。 安装的版本:SQL Server2017 目录 一、拉取镜像 二、运行容器 三、进入容器 四、远程连接 五、简单小结  一、拉取镜像 docker pull m

额外说明

SQL第03章_必知SQL-05_通配符过滤

SQL75 检索产品名称和描述(一) 描述 Products表 prod_name prod_desc a0011 usb a0019 iphone13 b0019 gucci t-shirts c0019 gucci toy d0019 le

额外说明

SQL语句练习02

1. 创建学生表 S(命名格式“姓名拼音_三位学号_s”,如 LBJ_023_s)并插入数据 create table LYL_116_s (S# varchar(4) primary key,  Sname varchar(9), Sage int,

额外说明

移动电商——Flutter-商品列表后台接口调试

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技am

额外说明

Unity中Shader实现UI流光效果

文章目录 前言 一、实现思路1: 1、采集两张贴图,一张是主纹理,一张是扫光纹理 2、在 v2f 定义一个二维变量 “uv2” 来存放 uv 偏移后的值 3、在顶点着色器中,仿照之前的 uv 流动效果,与 _Time相乘后存放于 uv2 中 4、最后,流

额外说明

van-popup() 点击空白处关闭弹窗

用:close-on-click-overlay属性来控制是否点击空白处关闭弹窗,true的时候点击空白处关闭,false反之。 <van-popup :close-on-click-overlay="true" position="bottom" :s

额外说明

Reduce join时报错Exception in thread "main" java.lang.NullPointerException

本文仅是此错误的一种特例情况,与一般空指针错误不同,所以写出来为大家作为参考 我做reduce join实验时,第一次运行程序没有出错,但是重复运行时却出现以下错误 问题就是下图中我们在第一次运行程序时产生的out5文件夹,reduce join默认处理

额外说明

[Web Chart系列之六] canvas Chart 导出图文件

介绍 使用SVG绘制的图形可以导出为svg 格式的文件,使用浏览器等可以查看。 是否可以导出为png, gif 格式的文件呢? 当然是可以。 只是在 web 直接创建和操作文件是不建议的,而且存在各浏览器兼容的问题, 比如IE使用ActiveX来创建新文

额外说明

springboot大文件上传、分片上传、断点续传、秒传的实现

对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传,从上传的效率来看,利用多线程并发上传能够达到最大效率。 一、为什么要使用该技术方案 如果前端一次性上传一个非常大的

ads via 小工具