深入理解java * 的两种实现方式(JDK/Cglib)
作者:PerKins.Zhu 发布时间:2023-11-26 13:29:52
标签:cglib,jdk,java
什么是代理模式?
代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作。在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能。
为什么要使用代理模式?
通过代理模式可以实现对目标类调用的控制、在目标类调用前/后进行一些不属于目标类的操作,如:数据验证、预处理、后处理、异常处理等
什么是静态代理什么是 * ?
静态代理:代理类只能实现对”特定接口的实现类“进行代理
* :代理类可以实现对多种类的代理
jdk代理和cglib代理区别在哪里?
jdk * :代理所有“实现的有接口”的目标类
cglib * :代理任意一个目标类,但对final类和方法无法代理
不同点:jdk * 的目标类必须实现的有接口,因为在调用Proxy.newProxyInstance()的时候需要传入目标类的接口类。而cglib不做此限制。
下面看代码分析:
定义一个Person接口
package com.zpj.designMode.proxy;
//定义一个Person接口
public interface Person {
public void doWork();
}
添加一个实现类:MrLi
package com.zpj.designMode.proxy;
//添加一个实现类
public class MrLi implements Person {
@Override
public void doWork() {
System.out.println("-----doWork");
}
}
静态代理:
添加一个静态代理类Proxy
package com.zpj.designMode.proxy;
//静态代理,代理必须和目标类实现共同的接口
public class Proxy implements Person {
private Person person;// 被代理人
//这里的目标类型决定了该代理类只能代理实现了Person接口的实例,而不能接收其他类型参数,这也就是静态代理的局限性
public Proxy(Person person) {
this.person = person;
}
@Override
public void doWork() {
System.out.println("doSomething-----start");
person.doWork();
System.out.println("doSomething-----end");
}
}
静态代理测试程序:
package com.zpj.designMode.proxy;
public class Run {
public static void main(String[] args) {
MrLi li = new MrLi();
Proxy proxy = new Proxy(li);
//调用处直接调用代理进行目标方法的操作。
proxy.doWork();
}
}
JDK * :
添加一个代理JDKProxy,该代理实现InvocationHandler接口且覆写invoke方法。
package com.zpj.designMode.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/***
@author Perkins Zhu
@date 2017年3月13日 上午8:41:10
*/
public class JDKProxy implements InvocationHandler {
private Object person;// 被代理人
//这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了 * 。但是要注意下面的newProxyInstance()中的参数
public Object getInstance(Object person) {
this.person = person;
//与cglib的区别在于这里构建代理对象的时候需要传入被代理对象的接口对象,第二个参数。而cglib不需要被代理对象实现任何接口即可
return Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("doSomething---------start");
method.invoke(person, args);
System.out.println("doSomething---------end");
return null;
}
}
JDK * 测试程序
package com.zpj.designMode.proxy.jdk;
import com.zpj.designMode.proxy.MrLi;
import com.zpj.designMode.proxy.Person;
/***
* @author Perkins Zhu
* @date 2017年3月13日 上午8:51:31
*/
public class Run {
public static void main(String[] args) {
Person person = (Person) new JDKProxy().getInstance(new MrLi());
//注意这里的person不是目标类person,而是代理类person:debug的时候显示null,有'$'标识符
person.doWork();
}
}
Cglib * :
添加一个CglibProxy代理,同时实现MethodInterceptor接口。
package com.zpj.designMode.proxy.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/***
* @author Perkins Zhu
* @date 2017年3月13日 上午9:02:54
*/
public class CglibProxy implements MethodInterceptor {
private Object targetObject;
// 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了 *
public Object getInstance(Object target) {
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//注意该处代理的创建过程
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理对象
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
System.out.println("doSomething---------start");
obj = method.invoke(targetObject, args);
System.out.println("doSomething---------end");
return obj;
}
}
Cglib * 测试程序
package com.zpj.designMode.proxy.cglib;
import com.zpj.designMode.proxy.MrLi;
import com.zpj.designMode.proxy.Person;
/***
@author Perkins Zhu
@date 2017年3月13日 上午9:07:38
*/
public class Run {
public static void main(String[] args) {
Person person = (Person)new CglibProxy().getInstance(new MrLi());
person.doWork();
}
}
仔细对比Proxy、CglibProxy和JDKProxy区分静态代理、JDK * 和Cglib * 的异同点!
来源:http://www.cnblogs.com/PerkinsZhu/p/6549211.html
0
投稿
猜你喜欢
- 本文实例讲述了Hibernate批量处理海量数据的方法。分享给大家供大家参考,具体如下:Hibernate批量处理海量其实从性能上考虑,它是
- Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面。在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制
- 为什么要重复造轮子你可能会问,Spring已经自带了全局异常拦截,为什么还要重复造轮子呢?这是个好问题,我觉得有以下几个原因装逼Spring
- 多线程的创建,方式一:继承于Thread类1.创建一个继承于Thread类的子类2.重写Thread类的run()--->将此线程执行
- 一 :问题背景问题:当查询接口较复杂时候,数据的获取都需要[远程调用],必然需要花费更多的时间。 假如查询文章详情页面,需要如下标注的时间才
- 环境:VS2019+Qt5.121. CLR库安装 &nb
- ActiveMQ是什么ActiveMQ是消息队列技术,为解决高并发问题而生ActiveMQ生产者消费者模型(生产者和消费者可以跨平台、跨系统
- 前言Kotlin一个强大之处就在于它的扩展函数,巧妙的运用这些扩展函数可以让你写出的代码更加优雅,阅读起来更加流畅,下面总结了在开发中经常用
- reduce()简介Reduce 原意:减少,缩小根据指定的计算模型将Stream中的值计算得到一个最终结果解释:reduce 操
- spring注入枚举类型作为参数//定义枚举类型public enum ReportType { MONTH,WE
- 本文主要给大家介绍java的InputStream 流的使用。(1)FileInputstream: 子类,读取数据的通道使用步骤:1.获取
- 前2天有读者问到是否有带分页功能的表格控件,今天分页功能的表格控件详细解析。PaginatedDataTablePaginatedDataT
- 1.接口中的默认方法和静态方法Java 8中允许接口中包含具有具体实现的方法,该方法称为 “默认方法” ,默认方法使用 default 关键
- 简介Springboot Admin是一个管理和监控Springboot项目的组件,分为服务端和客户端,两端通过http进行通信。由于其轻量
- SpringDataJpa创建中间表//fetch=FetchType.EAGER 关闭懒加载 相当于hibernate中的lazy=fal
- 介绍:%是求余运算符,也叫模除运算符,用于求余数。%要求两个操作数均为整数(或可以隐式转换成整数的类型)。标准规定:如果%左边的操作数为负数
- Jetty和tomcat的比较Tomcat和Jetty都是一种Servlet引擎,他们都支持标准的servlet规范和JavaEE的规范。架
- 我们经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环的效果。看到那样的效果,相信大家都会想到ViewPag
- 说明:本文记录如何在Idea下,利用Maven管理项目,并整合SSM(Spring + Spring MVC +Mybatis)框架,实现简
- 前言上一篇文章已经介绍了fluent-mybatis项目的构建,文章地址:Java Fluent Mybatis实战之构建项目与代码生成篇上