- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java动态代理(设计模式)代码详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
基础:需要具备面向对象设计思想,多态的思想,反射的思想; 。
java动态代理机制的出现,使得java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。通过阅读本文,读者将会对java动态代理机制有更加深入的理解。本文首先从java动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现.
代理模式的基本概念和分类 。
代理模式:为其他对象提供一个代理,来控制对这个对象的访问。代理对象起到中介作用,可以去掉服务或者增加额外的服务,或者引用别人的话:“代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。” 。
代理模式在开发中的应用场景 。
远程代理:为不同地理的对象提供局域网代表对象.
虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。比如网页中的先显示文字再显示图片.
保护代理:控制不同用户的访问权限。比如:只有当客户注册成功之后,才可以进行增删改查等操作.
智能引用代理:提供对目标代理额外的服务.
代理模式的实现方式 。
使用继承和聚合实现动态代理,哪种更好呢! 。
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
|
public
interface
moveable {
public
void
move();
}
public
class
car
implements
moveable{
@override
public
void
move() {
try
{
thread.sleep(
new
random().nextint(
1000
));
system.out.println(
"……行驶中……"
);
}
catch
(interruptedexception e) {
// todo auto-generated catch block
e.printstacktrace();
}
}
}
public
class
car2
extends
car{
@override
public
void
move()
{
//分离代码,增加业务逻辑
long
starttime=system.currenttimemillis();
system.out.println(
"汽车开始行驶……"
);
super
.move();
long
endtime=system.currenttimemillis();
system.out.println(
"汽车结束行驶……时间:"
+(endtime-starttime)+
"ms"
);
}
}
|
继承方式实现代理 。
moveablecar2=newcar2(); car2.move(),
聚合方式实现代理 。
carcar=newcar(); moveablem=newcar3(car); m.move(),
总结 。
使用继承方式不够灵活,当功能叠加的时候,只能臃肿的扩展代理类; 使用聚合的方式,代理之间可以相互传递,灵活的组合代理; 。
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
|
public
class
carlogproxy
extends
car{
@override
public
void
move()
{
//分离代码,增加业务逻辑
long
starttime=system.currenttimemillis();
system.out.println(
"日志开始……"
);
super
.move();
long
endtime=system.currenttimemillis();
system.out.println(
"日志结束……"
);
}
}
public
class
cartimeproxy
implements
moveable {
public
cartimeproxy(car car)
{
super
();
this
.car=car;
}
private
carcar;
@override
public
void
move() {
//分离代码,增加业务逻辑
long
starttime=system.currenttimemillis();
system.out.println(
"汽车开始行驶……"
);
car.move();
long
endtime=system.currenttimemillis();
system.out.println(
"汽车结束行驶……时间:"
+(endtime-starttime)+
"ms"
);
}
}
@test
:
car car =
new
car();
cartimeproxy ctp=
new
cartimeproxy(car);
carlogproxy clp=
new
carlogproxy(ctp);
clp.move();
//还可以通过接口相互传递代理实例
carlogproxy clp1=
new
carlogproxy(car);
cartimeproxy ctp1=
new
cartimeproxy(clp1);
ctp1.move();
|
jdk动态代理和cglib动态代理 。
jdk动态代理 。
代理实现 。
如果不同的对象要实现相同功能的代理类,应该如何处置?
此时可以试着将其集成在同一个代理类中-----动态代理:实现对不同类/不同方法的代理; 。
大致过程如下:
java动态代理类位于java.lang.reflect包下,一般主要涉及到一下两个类:
(1)interfaceinvocationhandler:该接口中仅定义了一个方法publicobjectinvoke(objectobj,methodmethod,object[]args) 。
obj:一般是指代理类 。
method:是被代理的方法 。
args为该方法的参数数组.
这个抽象的方法在代理类中动态实现.
(2)proxy:该类即为动态代理类 。
statixobjectnewproxyinstance(classloaderloader,class[]interfaces,invocationhandlerh) 。
返回甙类类的一个实例,返回后的代理类可以当做被代理类使用(可以使用被代理类在接口中声明过的方法); 。
实现实例:
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
|
@ timehandler
public
class
timehandler
implements
invocationhandler {
public
timehandler(object target) {
super
();
this
.target = target;
}
private
objecttarget;
/*
* 参数:
* proxy 被代理对象
* method 被代理对象的方法
* args 方法的参数
*
* 返回值:
* object 方法返回值
*/
@override
public
object invoke(object proxy, method method,object[] args)
throws
throwable {
long
starttime=system.currenttimemillis();
system.out.println(
"汽车开始行驶……"
);
method.invoke(target);
long
endtime=system.currenttimemillis();
system.out.println(
"汽车结束行驶……时间:"
+(endtime-starttime)+
"ms"
);
return
null
;
}
}
|
1
2
3
4
5
|
@被代理类的接口
public
interface
moveable {
public
void
move();
}
@被代理的类
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
car
implements
moveable{
@override
public
void
move() {
try
{
thread.sleep(
new
random().nextint(
1000
));
system.out.println(
"……行驶中……"
);
}
catch
(interruptedexception e) {
// todo auto-generated catch block
e.printstacktrace();
}
}
}
|
@测试 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
test {
/**
* jdk动态代理的测试类
*/
public
static
void
main(string[] args) {
car car=
new
car();
invocationhandler h=
new
timehandler(car);
class
<?>cls=car.getclass();
/*
* loader 类加载器
* interfaces 实现接口
* h invocationhandler
*/
moveable m=(moveable)proxy.newproxyinstance(cls.getclassloader(),cls.getinterfaces(),h);
m.move();
}
}
|
&&测试结果 。
梳理总结 。
所为的dynamicproxy是这样一种class:
它是在运行时生成的class,该class需要实现一组interface,使用动态代理类的时候,必须实现invocationhandler接口.
jdk动态代理的一般步骤 。
1.创建一个实现接口invocationhandler的类,它必须实现invoke() 。
2.创建被代理的类以及接口 。
3.调用proxy的静态方法,创建一个代理类 。
newproxyinstance(classloaderloader,class[]interfaces,invocationhandlerh) 。
4.通过代理调用方法 。
cglib动态代理的实现 。
代理实现 。
@引入cglib-node-2.2.jar包 。
@cglibproxy拦截类实现接口methodinterceptor:重写intercept拦截方法 。
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
|
public
class
cglibproxy
implements
methodinterceptor {
private
enhancerenhancer=
new
enhancer();
public
object getproxy(
class
cl)
{
//设置创建子类的类
enhancer.setsuperclass(cl);
enhancer.setcallback(
this
);
return
enhancer.create();
}
/*
* 拦截所有目标类方法的调用
* object 目标类的实例
* m 目标方法的反射对象
* args 方法的参数
* proxy 代理类的实例
*
*/
@override
public
object intercept(object obj, method m,object[] args, methodproxy proxy)
throws
throwable
{
system.out.println(
"日志开始……"
);
//代理类调用父类的方法
proxy.invokesuper(obj, args);
system.out.println(
"日志结束……"
);
return
null
;
}
}
|
@被代理类train 。
1
2
3
4
5
6
|
public
class
train {
public
void
move()
{
system.out.println(
"火车行驶中……"
);
}
}
|
@测试类 。
1
2
3
4
5
6
7
8
9
10
|
public
class
test {
/**
* cglibproxy动态代理测试类
*/
public
static
void
main(string[] args) {
cglibproxy proxy=
new
cglibproxy();
train t=(train)proxy.getproxy(train.
class
);
t.move();
}
}
|
##测试结果:
梳理总结 。
使用cglibproxy实现动态代理的一般步骤 。
1、创建类实现接口methodinterceptor,并重写intercept方法 。
2、创建被代理类 。
3、调用代理类自定义的方法,得到一个代理实例 。
4、通过代理实例调用被代理类的需要执行的方法 。
比较总结 。
jdk动态代理 。
1、只能代理实现了接口的类 。
2、没有实现接口的类不能实现jdk的动态代理 。
cglib动态代理 。
1、针对类来实现代理 。
2、对执行目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用.
模拟代理产生步骤 。
思路:
实现功能:通过proxy的newproxyinstance返回代理对象 。
1、声明一段源码(动态产生代理) 。
2、编译源码(jdkcompilerapi)产生新的类(代理类) 。
3、将这个类load到内存当中,产生一个新的对象(代理对象) 。
4、返回代理对象 。
完善动态代理实现 。
首先得到系统编译器,通过编译器得到文件管理者,然后获取文件,然后编译器执行编译任务,完成编译之后,将class文件加载到类加载器中,通过构造方法得到实例,然后调用newinstance()接收一个对象的实例.
(1)拿到编译器javacompilercompiler=toolprovider.getsystemjavacompiler(),
(2)文件管理者standardjavafilemanagerfilemgr=compiler.getstandardfilemanager(null,null,null),
(3)获取文件iterableunits=filemgr.getjavafileobjects(filename),
(4)编译任务compilationtaskt=compiler.gettask(null,filemgr,null,null,null,units),
(5)load到内存 。
classloadercl=classloader.getsystemclassloader(),
classc=cl.loadclass(”com.imooc.proxy.$proxy0”),
(6)通过代理对象的构造器构造实例 。
constructorctr=c.getconstructor(infce),
ctr.newinstance(newcar()),
------- 。
上说所说,内部的业务逻辑是硬编码的,如何实现真正的动态代理,动态的指定业务逻辑呢?
1、需要创建一个事务处理器,首先创建一个接口也就是invocationhandler,为了模拟jdk,这里把接口的名字和jdk事务处理器名称一样,同样写一个方法叫做invoke(),用来表示对某个对象的某个方法进行业务处理,所以需要把某个对象以及对象的方法作为invoke()方法的参数传递进来,invoke(objectobj,methodmethod),方法作为参数使用到了java反射,需要把此包引入。这样invocationhandler接口就完成了.
2、创建事务处理实现类比如说时间代理timerproxy,实现了invocationhandler接口,这样结构就成了 。
1
2
3
4
5
6
7
8
|
——————timerproxyimplementsinvocationhandler{
————————-
@override
————————-voidinvoke(objectobj,methodmethod){
———————————
//业务逻辑<br>
—————————————method.invoke(目标对象,参数);
————————————
//业务逻辑<br>
——————————}
—————————}
|
需要将目标对象传入,没有参数可以不写参数,创建代理对象的构造方法,初始化目标对象 。
3、在proxy类的newproxyinstance()方法中,除了要把目标class接口作为参数外,还需要把事务处理器invocationhandler传进去,然后更改创建实例对象中硬编码的部分用事务处理器方法替代即可。难点在于字符串的拼接.
总结 。
在我们项目中代理模式有自己的实际意义,比如说我们想要调用某个jar包下的某个类,可以在调用这个类之前之后添加一些特殊的业务逻辑,这种方式也叫作aop面向切面编程。(在不改变原有功能的基础上,添加额外的功能。) 。
以上就是本文关于java动态代理(设计模式)代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! 。
原文链接:http://blog.csdn.net/csdn_terence/article/details/52860221 。
最后此篇关于Java动态代理(设计模式)代码详解的文章就讲到这里了,如果你想了解更多关于Java动态代理(设计模式)代码详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
全称“Java Virtual Machine statistics monitoring tool”(statistics 统计;monitoring 监控;tool 工具) 用于监控虚拟机的各种运
主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。 可以转载,但请注明出处。  
1>单线程或者单进程 相当于短链接,当accept之后,就开始数据的接收和数据的发送,不接受新的连接,即一个server,一个client 不存在并发。 2>循环服务器和并发服务器
详解 linux中的关机和重启命令 一 shutdown命令 shutdown [选项] 时间 选项: ?
首先,将json串转为一个JObject对象: ? 1
matplotlib官网 matplotlib库默认英文字体 添加黑体(‘SimHei')为绘图字体 代码: plt.rcParams['font.sans-serif']=['SimHei'
在并发编程中,synchronized关键字是常出现的角色。之前我们都称呼synchronized关键字为重量锁,但是在jdk1.6中对synchronized进行了优化,引入了偏向锁、轻量锁。本篇
一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配置拿到的是Connection对象。  
实例如下: ? 1
1. MemoryCahe NetCore中的缓存和System.Runtime.Caching很相似,但是在功能上做了增强,缓存的key支持object类型;提供了泛型支持;可以读缓存和单个缓存
argument是javascript中函数的一个特殊参数,例如下文,利用argument访问函数参数,判断函数是否执行 复制代码 代码如下: <script
一不小心装了一个Redis服务,开了一个全网的默认端口,一开始以为这台服务器没有公网ip,结果发现之后悔之莫及啊 某天发现cpu load高的出奇,发现一个minerd进程 占了大量cpu,googl
今天写这个是为了 提醒自己 编程过程 不仅要有逻辑 思想 还有要规范 代码 这样可读性 1、PHP 编程规范与编码习惯最主要的有以下几点: 1 文件说明 2 funct
摘要:虚拟机安装时一般都采用最小化安装,默认没有lspci工具。一台测试虚拟网卡性能的虚拟机,需要lspci工具来查看网卡的类型。本文描述了在一个虚拟机中安装lspci工具的具体步骤。 由于要测试
1、修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统
目录 算术运算符 基本四则运算符 增量赋值运算符 自增/自减运算符 关系运算符 逻
如下所示: ? 1
MapperScannerConfigurer之sqlSessionFactory注入方式讲解 首先,Mybatis中的有一段配置非常方便,省去我们去写DaoImpl(Dao层实现类)的时间,这个
Linux的网络虚拟化是LXC项目中的一个子项目,LXC包括文件系统虚拟化,进程空间虚拟化,用户虚拟化,网络虚拟化,等等,这里使用LXC的网络虚拟化来模拟多个网络环境。 本文从基本的网络设备讲
? 1
我是一名优秀的程序员,十分优秀!