Spring中的两种代理JDK和CGLIB的区别浅谈
作者:飞--鹰 发布时间:2023-01-04 19:05:05
一、原理区别:
Java * 是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib * 是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的 * 实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK * 和CGLIB之间转换
如何强制使用CGLIB实现AOP?
(1)添加CGLIB库,SPRING_HOME/cglib/.jar
(2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK * 和CGLIB字节码生成的区别?
(1)JDK * 只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
二、代码实现
package com.fy.spring.proxy;
public interface UserManager {
public void addUser(String id, String password);
public void delUser(String id);
}
package com.fy.spring.proxy;
public class UserManagerImpl implements UserManager {
public void addUser(String id, String password) {
System.out.println(".: 掉用了UserManagerImpl.addUser()方法! ");
}
public void delUser(String id) {
System.out.println(".: 掉用了UserManagerImpl.delUser()方法! ");
}
}
JDK * 类
package com.fy.spring.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* JDK * 类
*
*
*/
public class JDKProxy implements InvocationHandler {
private Object targetObject;//需要代理的目标对象
public Object newProxy(Object targetObject) {//将目标对象传入进行代理
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);//返回代理对象
}
public Object invoke(Object proxy, Method method, Object[] args)//invoke方法
throws Throwable {
checkPopedom();//一般我们进行逻辑处理的函数比如这个地方是模拟检查权限
Object ret = null; // 设置方法的返回值
ret = method.invoke(targetObject, args); //调用invoke方法,ret存储该方法的返回值
return ret;
}
private void checkPopedom() {//模拟检查权限的例子
System.out.println(".:检查权限 checkPopedom()!");
}
}
CGLibProxy * 类
package com.fy.spring.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* CGLibProxy * 类的实例
*
*
*/ public class CGLibProxy implements MethodInterceptor {
private Object targetObject;// CGLib需要代理的目标对象
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理对象
}
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
if ("addUser".equals(method.getName())) {// 过滤方法
checkPopedom();// 检查权限
}
obj = method.invoke(targetObject, args);
return obj;
}
private void checkPopedom() {
System.out.println(".:检查权限 checkPopedom()!");
}
}
测试类:
public class Client {
public static void main(String[] args) {
UserManager userManager = (UserManager) new CGLibProxy()
.createProxyObject(new UserManagerImpl());
System.out.println("-----------CGLibProxy-------------");
userManager.addUser("tom", "root");
System.out.println("-----------JDKProxy-------------");
JDKProxy jdkPrpxy = new JDKProxy();
UserManager userManagerJDK = (UserManager) jdkPrpxy
.newProxy(new UserManagerImpl());
userManagerJDK.addUser("tom", "root");
}
}
运行结果:
-----------CGLibProxy-------------
检查权限 checkPopedom()!
掉用了UserManagerImpl.addUser()方法!
-----------JDKProxy-------------
检查权限 checkPopedom()!
掉用了UserManagerImpl.addUser()方法!
JDK代理是不需要以来第三方的库,只要要JDK环境就可以进行代理,它有几个要求
实现InvocationHandler
使用Proxy.newProxyInstance产生代理对象
被代理的对象必须要实现接口
CGLib 必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理
在Hibernate中的 * 其实现考虑到不需要其他接口的条件Hibernate中的相关代理采用的是CGLib来执行。
希望本文所述对你有所帮助,Spring中的两种代理JDK和CGLIB的区别浅谈内容就给大家介绍到这里了。希望大家继续关注我们的网站!想要学习java可以继续关注本站。
来源:http://blog.csdn.net/u013126379/article/details/52121096
猜你喜欢
- 在学习Spring的过程中,留下一下痕迹。代理模式,其实就是让别人做同样的事情,但是别人却不仅将我的事情做了,还会把他的事情也做了,换言之,
- 有时候需要根据条件查询得出的数据较多,需要分页显示到页面上。这时点击下一页就不方便每次带查询条件在数据库中分页。可以在list中进行分页。p
- 顺序语句顺序顾名思义就是程序自上而下执行public class User { public static voi
- 最近在鼓捣spring -boot ,真好用,学习到jpa.通过生成Entity 文件,能够快速的生成数据库,并且使用JpaReposito
- 本文实例讲述了Java正则验证电话,手机,邮箱,日期,金额的方法。分享给大家供大家参考,具体如下:package com.hooypay.t
- 概述:Flutter 标签类控件大全ChipFlutter内置了多个标签类控件,但本质上它们都是同一个控件,只不过是属性参数不同而已,在学习
- 背景知识Fluent Interface是一种通过连续的方法调用以完成特定逻辑处理的API实现方式,在代码中引入Fluent Interfa
- 本文实例讲述了C#实现Xml序列化与反序列化的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// X
- 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很
- Mutex 中文为互斥,Mutex 类叫做互斥锁。它还可用于进程间同步的同步基元。Mutex 跟 lock 相似,但是 Mutex 支持多个
- 一、ArrayListArrayList是一个可以处理变长数组的类型,这里不局限于“数”组,ArrayList是一个泛型类,可以存放任意类型
- 概要:流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性
- 程序如下:View Code /* * Hanoi塔游戏 问题描述: * 汉诺塔:汉诺塔(又称河内塔)问
- 1、一次性添加多行注释的快捷键首先选中要注释区域,然后ctrl+/ 这个是多行代码分行注释,每行一个注释符号ctrl+shift+/ 这个是
- 在使用JDBC的时候,数据库据连接是非常宝贵的资源。为了复用这些资源,可以将连接保存在一个队列中。当需要的时候可以从队列中取出未使用的连接。
- 完整代码已上传到GitHub。Web端体验地址:http://47.116.72.33/(只剩一个月有效期)apk下载地址:https://
- SpringBoot Data JPA实现 一对多、多对一关联表查询开发环境IDEA 2017.1Java1.8SpringBoot 2.0
- Unity脚本中枚举类型在inspector面板中文显示,供大家参考,具体内容如下效果:工具脚本:ChineseEnumTool.csusi
- 1、java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicL
- 棋牌类游戏是目前比较火的游戏之一。今天本文就以实例形式实现洗牌游戏。本文实例所采用的算法是:遍历每个位置上的牌,然后与随机位置上的牌交换。运