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

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

Java 额外说明

收录于:97天前

代理模式是一种常用的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

. . .

相关推荐

额外说明

海思下载uboot、内核、文件系统

通过Hitool下载三个文件,注意hitool本地pc配置。 这里需要注意的是,spiflash的大小配置,这里只要注意文件系统的长度就好, 如果,uboot和内核占用5M大小,那麽文件系统的开始地址为5M,长度是spiflash的大小-5M,比如32M

额外说明

zk acl -自定义用户权限

    工具类      

额外说明

SQL注入-联合查询注入union

目录 SQL注入的一库三表 union联合查询注入注意事项 MySQL函数利用         1、常用函数         2、连接字符串函数 联合查询注入union 利用前提 联合注入的过程 1、先判断有没有注入点

额外说明

将表情符号表达式插入 MySQL 数据库时出现问题?字符串值不正确:'\\xF0\\x9F\\x98\\x8D\\xF0\\x9F...'Mysql从utf8批量转换为utf8mb4

先说解决办法: 方法一:直接修改数据库、表、字段的编码为utf8mb4(推荐使用); 方法二:使用Java转码解决; 背景: 最近在维护流控系统时,部分销售反馈无法提交工作流,以及发现评论发emoji表情 (图标网站:链接地址---)直接存入mysql会

额外说明

Web渗透测试-实战 方法 思路 总结

尽可能的搜集目标的信息 端口信息 DNS信息 员工邮箱 信息搜集的分类 1、主动式信息搜集(可获取到的信息较多,但易被目标发现) 2、通过直接发起与被测目标网络之间的互动来获取相关信息,如通过Nmap扫描目标系统。 3、被动式信息搜集(搜集到的信息较少,

额外说明

pom.xml出现“java.lang.OutOfMemoryError: Java heap space”问题的解决办法

这个问题真的是解决了好久,万万没有想到原因竟然是这个!!! 问题描述: gitLab上下载了一个新的项目,idea也是新搞得,配置完maven,jdk这几项之后,项目还是报错,各处爆红那种,就以为是我的maven或者jdk有问题,就各种查看环境变量和更换

额外说明

Linux命令200例:mdel删除指定目录下的多个文件

-作者简介,黑夜开发者,全栈领域新星创作者✌,2023年6月csdn上海赛道top4。 -本文已收录于专栏:Linux命令大全。 -本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入讲解。欢迎提前锁定关注。 文章目录 一、背景 二、

额外说明

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

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

额外说明

springboot升级到2.7.12版本后启动报错 找不到符号符号:类 PaginationInterceptor

一、报错如下 Cannot resolve symbol ‘PaginationInterceptor’ 二、报错原因 springboot升级到2.7.12之后,mybatis-puls分页插件版本也会随之升级,mybatis-puls分页插件升级到3

额外说明

Java JDBC篇1——初识JDBC

Java JDBC篇1——初识JDBC Java DataBase Connectivity Java 数据库连接(Java语言操作数据库) 1、什么是JDBC 其实是官方定义的一套操作所有关系型数据库的规则(接口),各个数据库厂商去实现这套接口,提供数

ads via 小工具