- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章jdk动态代理和cglib动态代理详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
如上图,代理模式可分为动态代理和静态代理,我们比较常用的有动态代理中的jdk动态代理和cglib代理,像spring框架、hibernate框架中都采用了jdk动态代理,下面将结合代码阐述两种代理模式的使用与区别.
静态代理的代理对象和被代理对象在代理之前就已经确定,它们都实现相同的接口或继承相同的抽象类。静态代理模式一般由业务实现类和业务代理类组成,业务实现类里面实现主要的业务逻辑,业务代理类负责在业务方法调用的前后作一些你需要的处理,如日志记录、权限拦截等功能…实现业务逻辑与业务方法外的功能解耦,减少了对业务方法的入侵。静态代理又可细分为:基于继承的方式和基于聚合的方式实现.
场景:假设一个预减库存的操作,需要在预减的前后加日志记录(我这里是springboot项目) 。
1
2
3
4
5
6
7
|
/**
* 业务实现类接口
*/
public
interface
orderservice {
//减库存操作
void
reducestock();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/**
* 业务实现类
*/
@slf4j
public
class
orderserviceimpl
implements
orderservice {
@override
public
void
reducestock() {
try
{
log.info(
"预减库存中……"
);
thread.sleep(
1000
);
}
catch
(exception e){
e.printstacktrace();
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 代理类
*/
@slf4j
public
class
orderservicelogproxy
extends
orderserviceimpl{
@override
public
void
reducestock() {
log.info(
"预减库存开始……"
);
super
.reducestock();
log.info(
"预减库存结束……"
);
}
}
|
1
2
3
4
5
6
7
8
|
/**
* 测试继承方式实现的静态代理
*/
@test
public
void
testorderserviceproxy(){
orderservicelogproxy proxy =
new
orderservicelogproxy();
proxy.reducestock();
}
|
输出结果 。
14:53:53.769 [main] info com.simons.cn.springbootdemo.proxy.orderservicelogproxy - 预减库存开始…… 14:53:53.771 [main] info com.simons.cn.springbootdemo.proxy.orderserviceimpl - 预减库存中…… 14:53:54.771 [main] info com.simons.cn.springbootdemo.proxy.orderservicelogproxy - 预减库存结束…… 。
可以看到,orderservicelogproxy已经实现了为orderserviceimpl的代理,通过代理类的同名方法来增强了业务方法前后逻辑.
聚合的意思就是把业务类引入到了代理类中,接口和业务实现类还是之前的orderservice、orderserviceimpl,代理类改为如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 聚合方式实现静态代理:代理类中引入业务类
*/
@slf4j
public
class
orderservicelogproxy2
implements
orderservice {
private
orderserviceimpl orderservice;
public
orderservicelogproxy2(orderserviceimpl orderservice) {
this
.orderservice = orderservice;
}
@override
public
void
reducestock() {
log.info(
"预减库存开始……"
);
orderservice.reducestock();
log.info(
"预减库存结束……"
);
}
}
|
1
2
3
4
5
6
7
8
9
|
/**
* 测试聚合方式实现的静态代理
*/
@test
public
void
testorderserviceproxy2() {
orderserviceimpl orderservice =
new
orderserviceimpl();
orderservicelogproxy2 proxy2 =
new
orderservicelogproxy2(orderservice);
proxy2.reducestock();
}
|
测试输出结果和上面的结果是一致的.
结合上面的代码来看,如果此时需要叠加代理功能,我不仅要记录预减日志,还要增加权限拦截功能,这个时候如果采用继承的方式的话,就得新建一个代理类,里面包含日志和权限逻辑;那要是再增加一个代理功能,又要新增代理类;如果要改变下代理功能的执行顺序,还是得增加代理类,结合上面分析来看,这样做肯定是不妥的。但是如果使用聚合方式的方式呢?我们稍微改造下上面使用的聚合方式实现的静态代理代码:
首先是日志代理类代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 聚合方式实现静态代理--日志记录功能叠加改造
*/
@slf4j
public
class
orderservicelogproxy3
implements
orderservice {
//注意,这里换成了接口
private
orderservice orderservice;
public
orderservicelogproxy3(orderservice orderservice) {
this
.orderservice = orderservice;
}
@override
public
void
reducestock() {
log.info(
"预减库存开始……"
);
orderservice.reducestock();
log.info(
"预减库存结束……"
);
}
}
|
然后是新增的权限验证代理类代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 聚合方式实现静态代理--日志记录功能叠加改造
*/
@slf4j
public
class
orderservicepermissionproxy
implements
orderservice {
//注意,这里换成了接口
private
orderservice orderservice;
public
orderservicepermissionproxy(orderservice orderservice) {
this
.orderservice = orderservice;
}
@override
public
void
reducestock() {
log.info(
"权限验证开始……"
);
orderservice.reducestock();
log.info(
"权限验证结束……"
);
}
}
|
测试用例 。
1
2
3
4
5
6
7
8
9
10
|
/**
* 测试聚合方式实现的静态代理-功能叠加
*/
@test
public
void
testorderserviceproxy3() {
orderserviceimpl orderservice =
new
orderserviceimpl();
orderservicelogproxy2 logproxy2 =
new
orderservicelogproxy2(orderservice);
orderservicepermissionproxy permissionproxy =
new
orderservicepermissionproxy(logproxy2);
permissionproxy.reducestock();
}
|
测试结果 。
16:00:28.348 [main] info com.simons.cn.springbootdemo.proxy.orderservicepermissionproxy - 权限验证开始…… 16:00:28.365 [main] info com.simons.cn.springbootdemo.proxy.orderservicelogproxy2 - 预减库存开始…… 16:00:28.365 [main] info com.simons.cn.springbootdemo.proxy.orderserviceimpl - 预减库存中…… 16:00:29.365 [main] info com.simons.cn.springbootdemo.proxy.orderservicelogproxy2 - 预减库存结束…… 16:00:29.365 [main] info com.simons.cn.springbootdemo.proxy.orderservicepermissionproxy - 权限验证结束…… 。
接下来,如果你需要调换一下代理类逻辑执行顺序问题,你只需要在使用(像测试一样)时调换一下实例化顺序即可实现日志功能和权限验证的先后执行顺序了,而不需要像继承方式一样去不断的新建代理类.
看完上面的静态代理,我们发现,静态代理模式的代理类,只是实现了特定类的代理,比如上面orderservicelogproxy实现的orderserviceimpl的代理,如果我还有个userservice也许要日志记录、权限校验功能,又得写双份的userservicelogproxy、userservicepermissionproxy代理类,里面的逻辑很多都是相同的,也就是说你代理类对象的方法越多,你就得写越多的重复的代码,那么有了动态代理就可以比较好的解决这个问题,动态代理就可以动态的生成代理类,实现对不同类下的不同方法的代理.
jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用业务方法前调用invocationhandler处理。代理类必须实现invocationhandler接口,并且,jdk动态代理只能代理实现了接口的类,没有实现接口的类是不能实现jdk动态代理。结合下面代码来看就比较清晰了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import
lombok.extern.slf4j.slf4j;
import
java.lang.reflect.invocationhandler;
import
java.lang.reflect.method;
/**
* jdk动态代理实现,必须实现invocationhandler接口
* invocationhandler可以理解为事务处理器,所有切面级别的逻辑都在此完成
*/
@slf4j
public
class
dynamiclogproxy
implements
invocationhandler {
//需要代理的对象类
private
object target;
public
dynamiclogproxy(object target) {
this
.target = target;
}
/**
* @param obj 代理对象
* @param method 对象方法
* @param args 方法参数
* @return
* @throws throwable
*/
@override
public
object invoke(object obj, method method, object[] args)
throws
throwable {
log.info(
"这里是日志记录切面,日志开始……"
);
//使用方法的反射
object invoke = method.invoke(target, args);
log.info(
"这里是日志记录切面,日志结束……"
);
return
invoke;
}
}
|
使用时代码 。
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 测试jdk动态代理实现的日志代理类
*/
@test
public
void
testdynamiclogproxy() {
orderserviceimpl orderservice =
new
orderserviceimpl();
class
<?> clazz = orderservice.getclass();
dynamiclogproxy logproxyhandler =
new
dynamiclogproxy(orderservice);
//通过proxy.newproxyinstance(类加载器, 接口s, 事务处理器handler) 加载动态代理
orderservice os = (orderservice) proxy.newproxyinstance(clazz.getclassloader(), clazz.getinterfaces(), logproxyhandler);
os.reducestock();
}
|
输出结果 。
16:35:54.584 [main] info com.simons.cn.springbootdemo.proxy.dynamiclogproxy - 这里是日志记录切面,日志开始…… 16:35:54.587 [main] info com.simons.cn.springbootdemo.proxy.orderserviceimpl - 预减库存中…… 16:35:55.587 [main] info com.simons.cn.springbootdemo.proxy.dynamiclogproxy - 这里是日志记录切面,日志结束…… 。
使用jdk动态代理类基本步骤:
1、编写需要被代理的类和接口(我这里就是orderserviceimpl、orderservice); 。
2、编写代理类(例如我这里的dynamiclogproxy),需要实现invocationhandler接口,重写invoke方法; 。
3、使用proxy.newproxyinstance(classloader loader,class<?>[] interfaces,invocationhandler h)动态创建代理类对象,通过代理类对象调用业务方法.
那么这个时候,如果我需要在代理类中叠加功能,该如何是好?比如不仅要日志,还新增权限认证,思路还是上面的聚合方式实现静态代理里的那样,贴下代码,先新增权限认证代理类 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import
lombok.extern.slf4j.slf4j;
import
java.lang.reflect.invocationhandler;
import
java.lang.reflect.method;
/**
* 基于jdk动态代理实现的权限认证代理类
*/
@slf4j
public
class
dynamicpermissionproxy
implements
invocationhandler{
private
object target;
public
dynamicpermissionproxy(object target) {
this
.target = target;
}
/**
* @param obj 代理对象
* @param method 对象方法
* @param args 方法参数
* @return
* @throws throwable
*/
@override
public
object invoke(object obj, method method, object[] args)
throws
throwable {
log.info(
"这里是权限认证切面,开始验证……"
);
object invoke = method.invoke(target,args);
log.info(
"这里是权限认证切面,结束验证……"
);
return
invoke;
}
}
|
然后使用时候,需要稍微改动下 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/**
* 测试jdk动态代理实现的日志、权限功能代理类
*/
@test
public
void
testdynamiclogandpermissproxy() {
orderserviceimpl orderservice =
new
orderserviceimpl();
class
<?> clazz = orderservice.getclass();
dynamiclogproxy logproxyhandler =
new
dynamiclogproxy(orderservice);
orderservice os = (orderservice) proxy.newproxyinstance(clazz.getclassloader(), clazz.getinterfaces(), logproxyhandler);
//注:这里把日志代理类实例对象传入权限认证代理类中
dynamicpermissionproxy dynamicpermissionproxy =
new
dynamicpermissionproxy(os);
orderservice os2 = (orderservice)proxy.newproxyinstance(os.getclass().getclassloader(),os.getclass().getinterfaces(),dynamicpermissionproxy);
os2.reducestock();
}
|
如上即可,后面还需要叠加功能代理类的话,按照上面的思路依次传入代理对象实例即可.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
hashmapproxytest {
public
static
void
main(string[] args) {
final
hashmap<string, object> hashmap =
new
hashmap<>();
map<string, object> mapproxy = (map<string, object>) proxy.newproxyinstance(hashmap.
class
.getclassloader(), hashmap.
class
.getinterfaces(),
new
invocationhandler() {
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
return
method.invoke(hashmap, args);
}
});
mapproxy.put(
"key1"
,
"value1"
);
system.out.println(mapproxy);
}
}
|
cglib是针对类来实现代理的,它会对目标类产生一个代理子类,通过方法拦截技术对过滤父类的方法调用。代理子类需要实现methodinterceptor接口。另外,如果你是基于spring配置文件形式开发,那你需要显示声明:
1
|
<aop:aspectj-autoproxy proxy-target-
class
=
"true"
/>
|
如果你是基于springboot开发,则一般在启动类头部显示的添加注解 。
1
|
@enableaspectjautoproxy
(proxytargetclass =
true
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
import
lombok.extern.slf4j.slf4j;
import
org.springframework.cglib.proxy.enhancer;
import
org.springframework.cglib.proxy.methodinterceptor;
import
org.springframework.cglib.proxy.methodproxy;
import
java.lang.reflect.method;
/**
* 基于cglib方式实现动态代理-日志功能
* 它是针对类实现代理的,类不用实现接口,cglib对目标类产生一个子类,通过方法拦截技术拦截所有的方法调用
*/
@slf4j
public
class
dynamiccgliblogproxy
implements
methodinterceptor {
private
enhancer enhancer =
new
enhancer();
public
object getproxyobj(
class
clazz) {
//设置父类
enhancer.setsuperclass(clazz);
enhancer.setcallback(
this
);
enhancer.setusecache(
false
);
return
enhancer.create();
}
/**
* 拦截所有目标类的方法调用
*
* @param o 目标对象
* @param method 目标方法
* @param args 方法参数
* @param methodproxy 代理类实例
* @return
* @throws throwable
*/
@override
public
object intercept(object o, method method, object[] args, methodproxy methodproxy)
throws
throwable {
log.info(
"这里是日志记录切面,日志开始……"
);
//代理类对象实例调用父类方法
object result = methodproxy.invokesuper(o, args);
log.info(
"这里是日志记录切面,日志结束……"
);
return
result ;
}
}
|
测试用例 。
1
2
3
4
5
6
7
8
9
|
/**
* 测试cglib实现的动态代理-日志功能
*/
@test
public
void
testgclibdynamiclogproxy(){
dynamiccgliblogproxy dynamiccgliblogproxy =
new
dynamiccgliblogproxy();
orderserviceimpl orderservice = (orderserviceimpl)dynamiccgliblogproxy.getproxyobj(orderserviceimpl.
class
);
orderservice.reducestock();
}
|
输出结果 。
17:41:07.007 [main] info com.simons.cn.springbootdemo.proxy.dynamiccgliblogproxy - 这里是日志记录切面,日志开始…… 17:41:07.038 [main] info com.simons.cn.springbootdemo.proxy.orderserviceimpl - 预减库存中…… 17:41:08.038 [main] info com.simons.cn.springbootdemo.proxy.dynamiccgliblogproxy - 这里是日志记录切面,日志结束…… 。
1、jdk动态代理只能代理实现了接口的类,没有实现接口的类不能实现jdk的动态代理; 。
2、cglib动态代理是针对类实现代理的,运行时动态生成被代理类的子类拦截父类方法调用,因此不能代理声明为final类型的类和方法; 。
1、静态代理在代理前就知道要代理的是哪个对象,而动态代理是运行时才知道; 。
2、静态代理一般只能代理一个类,而动态代理能代理实现了接口的多个类; 。
1、如果目标对象实现了接口,则默认采用jdk动态代理; 。
2、如果目标对象没有实现接口,则使用cglib代理; 。
3、如果目标对象实现了接口,但强制使用了cglib,则使用cglib进行代理 。
我们可以结合源码来看下,上面的选择:
补充 。
cglib实现的methodinterceptor接口在spring-core包下,你可能需要要引入 。
1
2
3
4
5
|
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-core</artifactid>
<version>
4.1
.
0
.release</version>
</dependency>
|
@slf4j是lombok里提供的,而且如果你在intellij idea开发工具中使用还需要安装lombok插件 。
@test是junit包下的,你可能需要引入 。
1
2
3
4
5
6
|
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>
4.11
</version>
<scope>test</scope>
</dependency>
|
本篇文章就到这里了,希望可以给你带来一些帮助,也希望您能够多多关注我的更多内容! 。
原文链接:https://blog.csdn.net/fanrenxiang/article/details/81939357 。
最后此篇关于jdk动态代理和cglib动态代理详解的文章就讲到这里了,如果你想了解更多关于jdk动态代理和cglib动态代理详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Spring不包含cglib依赖,cglib和spring cglib都有Enhancer类,一个是net.sf.cglib.proxy.Enhancer,另一个是org.springframewor
我正在尝试构建一个大型项目,但由于以下错误而失败: [INFO] -------------------------------------------------------------------
关闭。这个问题不符合 Stack Overflow guidelines 。它目前不接受答案。 想改善这个问题吗?更新问题,以便堆栈溢出为 on-topic。 7年前关闭。 Improve this
@Service public class TestService{ @DynamicReference private ITestProvider testProvider;
我有以下通用 cglib 方法拦截器实现: public class EntityInterceptor implements MethodInterceptor{ private Entit
假设我有一些 A 类,它具有 B 类的属性。 public class ClassA{ private ClassB classB; public ClassA(ClassB classB){ th
我正在使用 CGLib 来增强 A 类。 public class A { public void printName(){ System.out.println("guy");
我的 Controller 在其属性上使用了 @Value 注释,但是发生了一些奇怪的事情: 08:20:31.400 [main] ERROR Controller - postConstruct(
我想做的是序列化一个类实现一个命令模式,以便我稍后可以运行它。在最好的在所有世界中,我想序列化一个匿名类(我是意识到这个问题) 让事情变得有点复杂的是我在 Spring 的环境中并且我希望序列化的匿名
谁能给我一个 Java CGLib 的好例子 Mixin类用法?我一直在挖掘它们似乎都不够简单。 最佳答案 很简单: import static org.junit.Assert.*; import
在实际项目中,考虑到不同的数据使用者,我们经常要处理 VO、DTO、Entity、DO 等对象的转换,如果手动编写 setter/getter 方法一个个赋值,将非常繁琐且难维护。通常情况下,这类转换
代码如下: Patient patient = factory.createPatient(); Enhancer enhancer = new Enhancer(
我有两个类 @Component @Scope(proxyMode=ScopedProxyMode.TARGET_CLASS,value="session") public clas
代码是用 Scala 编写的,但希望 Java 程序员也能理解。 我有以下类(class): class SampleClass { def test(in: String) = "Hello w
我无法为 HttpURLConnection 类创建动态代理,因为它没有公共(public)构造函数来创建增强器。根据要求,我想创建一个动态代理以在运行时获取当前连接的详细信息。 我尝试使用this教
我想使用 cglib 作为我的 spring 代理机制。问题是,我有一些 bean 的依赖项由构造函数注入(inject),我无法更改。 CGLIB 似乎不太喜欢这样,不会让我实例化那个 bean。有
当尝试将 CGLIB 与回调过滤器(在数万个对象上)一起使用时,我注意到速度很糟糕,但我无法找到有关优化 CGLIB 的任何信息。 对于搜索/列表界面,系统从优化的查询中加载多个属性,并使用这些属性填
我正在为生产 spring batch 项目构建端到端测试框架。我们想使用内存中的嵌入式数据库(在我们的例子中是 hsqldb)进行这些测试,因为它运行得更快并且没有环境限制。由于这些数据库引擎之间的
借助 cglib,我可以使用以下代码创建延迟实例化的 BigInteger: Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Bi
我有一个正在开发的 Java 库,它使用 cglib 创建库用户提供的抽象类的子类,并提供自动生成的用户留在其中的抽象方法的实现。 我的问题是,如果有问题的方法具有包本地(即默认)可访问性,我生成的方
我是一名优秀的程序员,十分优秀!