- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章JAVA提高第八篇 动态代理技术由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
对于动态代理,学过aop的应该都不会陌生,因为代理是实现aop功能的核心和关键技术。那么今天我们将开始动态代理的学习:
1、引出动态代理 。
生活中代理应该是很常见的,比如你可以通过代理商去买电脑,也可以直接找厂商买电脑,最终都是买到了电脑。程序中也一样存在代理的情况,比如要为已经存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理、日志、计算方法耗时等等,那么我们会怎么做呢?
1.会编写一个与目标类拥有相同接口的代理类,代理类的每个方法调用目标类的相同方法,然后在调用方法前后加上系统功能所需要的代码.
2.如果采用工厂模式或者配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换.
样例如下:
1
2
3
4
5
|
public
class
x{
public
void
sayhello(){
syso:say hello;
}
}
|
现在我要在这个方法之前添加一个时间,方法之后添加一个时间,计算这个方法执行的时间一共是多少.如果我没有得到sayhello源码,那么我怎么做呢?写一个代理:
1
2
3
4
5
6
7
8
9
10
|
public
class
xproxy
{
private
x x;
public
void
sayhello
{
starttime:
x.syhello();
endtime;
}
}
|
说明:上面的是伪代码.
把开始时间和结束时间放在这个方法的前后就可以了. 通常我们让两个方法实现同一个接口.那么client想用x也可以,想用xproxy也可以了.具体的原理图,如下图所示:
2、创建动态代理类 。
现在试想一下,上面只是代理了一个目标类,如果多个目标类,那么是不是要创建n多个代理类呢?那样不是代码太不灵活且笨重了。当然不会.
java虚拟机可以在运行期间动态生成类,这种类是以字节码的形式生成出来的。这种动态生成的类往往呢就是代理类。即动态代理类.
jvm生成的动态代理类必须满足一定的条件,这就是必须实现一个或多个接口。所以jvm生成的动态代理只能用作具有相同接口的目标类的代理。(动态生成的类不是代理,我们只是吧这个类当成代理来用。) 。
proxy动态代理的api:
两个参数应该很容易理解:
第一个参数:我们知道任何一个字节码都是需要通过类加载器来加载的,那么这个动态生成的字节码也不例外,需要给它一个类加载器.
第二个参数:就是动态代理类生成,必须满足的一个条件,需要实现一个或者多个接口,否则这个生成的类字节码中就没有方法了,没有方法就失去了其功能意义.
下面我们动手来创建一个动态的代理类,大体思路为:
1.创建实现collection接口的动态类和查看其名称,分析proxy.getproxyclass方法的各个参数 。
2.编码列出动态类中的所有构造方法和参数签名 。
3.编码列出动态类中的所有方法和参数签名 。
4.创建动态类的实例对象:1)用反射获取构造方法 2)编写一个最简单的invocationhandle类 3)调用构造方法创建动态类的实例对象,并将编写的invocationhandle类的实例对象传递进去 4)打印创建对象和调用对象的没有返回的方法和getclass方法,演示调用其他有返回值方法报告了异常.
5)将创建动态类的实例对象的代理写成匿名内部类方式,简化代码.
样例分步实现如下:
(1)首先我们来完成前面3步:
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package
study.javaenhance;
import
java.lang.reflect.constructor;
import
java.lang.reflect.method;
import
java.lang.reflect.proxy;
import
java.util.collection;
public
class
proxytest
{
public
static
void
main(string[] args)
{
class
clazzproxy1 = proxy.getproxyclass(collection.
class
.getclassloader(),collection.
class
);
system.out.println(clazzproxy1.getname());
//上面输出的为一个类,那么一个类肯定有其构造方法和方法,下面我们来列出来
system.out.println(
"----------begin constructors list----------"
);
//1.列出构造方法
constructor[] constructors = clazzproxy1.getconstructors();
for
(constructor constructor : constructors)
{
string name = constructor.getname();
stringbuilder sbuilder =
new
stringbuilder(name);
sbuilder.append(
'('
);
class
[] clazzparams = constructor.getparametertypes();
for
(
class
clazzparam : clazzparams) {
sbuilder.append(clazzparam.getname()).append(
','
);
}
if
(clazzparams!=
null
&& clazzparams.length !=
0
)
sbuilder.deletecharat(sbuilder.length()-
1
);
sbuilder.append(
')'
);
system.out.println(sbuilder.tostring());
}
//2.列出这个类字节码中的所有方法
system.out.println(
"----------begin methods list----------"
);
method[] methods = clazzproxy1.getmethods();
for
(method method : methods){
string name = method.getname();
stringbuilder sbuilder =
new
stringbuilder(name);
sbuilder.append(
'('
);
class
[] clazzparams = method.getparametertypes();
for
(
class
clazzparam : clazzparams){
sbuilder.append(clazzparam.getname()).append(
','
);
}
if
(clazzparams!=
null
&& clazzparams.length !=
0
)
sbuilder.deletecharat(sbuilder.length()-
1
);
sbuilder.append(
')'
);
system.out.println(sbuilder.tostring());
}
}
}
|
输出结果如下:
$proxy0 ----------begin constructors list---------- $proxy0(java.lang.reflect.invocationhandler) ----------begin methods list---------- add(java.lang.object) hashcode() clear() equals(java.lang.object) tostring() contains(java.lang.object) isempty() addall(java.util.collection) iterator() size() toarray([ljava.lang.object;) toarray() remove(java.lang.object) containsall(java.util.collection) removeall(java.util.collection) retainall(java.util.collection) isproxyclass(java.lang.class) getproxyclass(java.lang.classloader,[ljava.lang.class;) getinvocationhandler(java.lang.object) newproxyinstance(java.lang.classloader,[ljava.lang.class;,java.lang.reflect.invocationhandler) wait() wait(long,int) wait(long) getclass() notify() notifyall() 。
可以看到所有的方法均是来自collection 和父类object中的方法,符合我们的预期结果。接下来我们进入第四步和第五步的实现:
首先,我们来创建这个动态代理类的实例。那么直接clazzproxy1.newinstance();可不可以呢?显然是不可以的嘛.我们刚刚说了,动态生成的这个代理类只有一个构造方法,有没有无参构造方法呢?没有啊.所以,创建 一个参数的构造方法.参数类型是java.lang.reflect.invocationhandler。 。
下面我们来实现:
1.定义一个上述接口的实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package
study.javaenhance;
import
java.lang.reflect.invocationhandler;
import
java.lang.reflect.method;
public
class
myinvocationhandler
implements
invocationhandler {
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
// todo auto-generated method stub
return
null
;
}
}
|
2.调用实现创建实例动态类:
1
2
3
4
5
6
7
8
|
//3.创建实例对象
system.out.println(
"----------begin create instance object----------"
);
constructor constructor = clazzproxy1.getconstructor(invocationhandler.
class
);
myinvocationhandler myinvocationhandler =
new
myinvocationhandler();
collection collection = (collection) constructor.newinstance(myinvocationhandler);
system.out.println(collection);
collection.clear();
//collection.size(); //报错,异常会发生,产生异常的原因在于其返回值为int类型,但是每一次调用一个方法都会调用到invoke方法,我们此时的invoke返回的为null,所以是没有办法转换为int类型的。
|
3.我们采用匿名内部类的方式优化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//3.1 采用匿名内部类方式进行创建
collection collection2 = (collection) constructor.newinstance(
new
invocationhandler()
{
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
// todo auto-generated method stub
return
null
;
}
});
system.out.println(collection2);
collection2.clear();
//collection2.size();
|
4.继续优化:思考如果我们每次都想上面方式去创建动态的代理类实在有点重复,那么这个是jdk的proxy类中提供了简单的方法直接去创建动态代理类,方式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//3.3 采用proxy 中提供的简单方法创建
collection collection3 = (collection)proxy.newproxyinstance(collection.
class
.getclassloader(),
new
class
[]{collection.
class
},
new
invocationhandler()
{
private
arraylist target =
new
arraylist();
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
return
method.invoke(target, args);
}
});
//system.out.println(collection3);
collection3.add(
"abc"
);
collection3.add(
"def"
);
collection3.add(
"hij"
);
system.out.println(collection3.size());
|
3、动态代理的原理简单分析 。
上面我们创建了动态代理类,下面我们分析下代理的原理:
。
下面在来看一个问题:
动态代理的工作原理图:
对上面的这个图,我们简单来说说:客户端动态生成代理类,然后调用代理类的方法,代理类内部调用handler.invoke()方法,在invoke中呢,我们又指向的目标类.这样就实现了代理了.我客户端调用代理的什么方法,invoke就只向目标类的同一个方法.而在指定目标类方法的前后呢,我们还可以做其他的操作,比如记录日志.图中用圈圈出来的部分就是代理类自己实现的功能了.这就是代理类的原理. 。
我们来做最后一步,将上面的动态生成的代理类,编写可生成代理和插入通告的通用方法:
。
test代码:
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package
study.javaenhance;
import
java.lang.reflect.constructor;
import
java.lang.reflect.invocationhandler;
import
java.lang.reflect.method;
import
java.lang.reflect.proxy;
import
java.util.arraylist;
import
java.util.collection;
public
class
proxytest
{
public
static
void
main(string[] args)
throws
exception
{
class
clazzproxy1 = proxy.getproxyclass(collection.
class
.getclassloader(),collection.
class
);
system.out.println(clazzproxy1.getname());
//上面输出的为一个类,那么一个类肯定有其构造方法和方法,下面我们来列出来
system.out.println(
"----------begin constructors list----------"
);
//1.列出构造方法
constructor[] constructors = clazzproxy1.getconstructors();
for
(constructor constructor : constructors)
{
string name = constructor.getname();
stringbuilder sbuilder =
new
stringbuilder(name);
sbuilder.append(
'('
);
class
[] clazzparams = constructor.getparametertypes();
for
(
class
clazzparam : clazzparams) {
sbuilder.append(clazzparam.getname()).append(
','
);
}
if
(clazzparams!=
null
&& clazzparams.length !=
0
)
sbuilder.deletecharat(sbuilder.length()-
1
);
sbuilder.append(
')'
);
system.out.println(sbuilder.tostring());
}
//2.列出这个类字节码中的所有方法
system.out.println(
"----------begin methods list----------"
);
method[] methods = clazzproxy1.getmethods();
for
(method method : methods){
string name = method.getname();
stringbuilder sbuilder =
new
stringbuilder(name);
sbuilder.append(
'('
);
class
[] clazzparams = method.getparametertypes();
for
(
class
clazzparam : clazzparams){
sbuilder.append(clazzparam.getname()).append(
','
);
}
if
(clazzparams!=
null
&& clazzparams.length !=
0
)
sbuilder.deletecharat(sbuilder.length()-
1
);
sbuilder.append(
')'
);
system.out.println(sbuilder.tostring());
}
//3.创建实例对象
system.out.println(
"----------begin create instance object----------"
);
constructor constructor = clazzproxy1.getconstructor(invocationhandler.
class
);
myinvocationhandler myinvocationhandler =
new
myinvocationhandler();
collection collection = (collection) constructor.newinstance(myinvocationhandler);
system.out.println(collection);
collection.clear();
//collection.size(); //报错,异常会发生,产生异常的原因在于其返回值为int类型,但是每一次调用一个方法都会调用到invoke方法,我们此时的invoke返回的为null,所以是没有办法转换为int类型的。
//3.1 采用匿名内部类方式进行创建
collection collection2 = (collection) constructor.newinstance(
new
invocationhandler()
{
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
// todo auto-generated method stub
return
null
;
}
});
system.out.println(collection2);
collection2.clear();
//collection2.size();
//3.3 采用proxy 中提供的简单方法创建
collection collection3 = (collection)proxy.newproxyinstance(collection.
class
.getclassloader(),
new
class
[]{collection.
class
},
new
invocationhandler()
{
private
arraylist target =
new
arraylist();
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
return
method.invoke(target, args);
}
});
//system.out.println(collection3);
collection3.add(
"abc"
);
collection3.add(
"def"
);
collection3.add(
"hij"
);
system.out.println(collection3.size());
system.out.println(collection3.getclass().getname());
//这个返回的是
system.out.println(
"----------begin create instance object 抽化----------"
);
//3.4抽出动态代理让目标对象和切面对象都是传入进去的
final
arraylist target =
new
arraylist();
collection collection4 = (collection)getproxy(target,
new
myadvice());
collection4.add(
"test1"
);
collection4.add(
"test2"
);
system.out.println(collection4.size());
}
private
static
object getproxy(
final
object target,
final
advice advice) {
object object = proxy.newproxyinstance(target.getclass().getclassloader(),
target.getclass().getinterfaces(),
new
invocationhandler()
{
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
advice.beforemethod(method);
object retvalue = method.invoke(target, args);
advice.aftermethod(method);
return
retvalue;
}
});
return
object;
}
}
|
4、实现类似spring的可配置的aop框架 。
首先,我们要完成的要求如下:
我们来模拟spring的工厂模式读取从配置文件传递过来的类。如果这个类是一个普通类则直接返回。如果是一个代理类,则创建代理对象,返回代理类.
具体的理论知识可以看上面的图片 。
首先创建一个beanfactory.java类。这是一个bean工厂,用于读取配置文件中的类 。
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package
study.javaenhance.aopframework;
import
java.io.ioexception;
import
java.io.inputstream;
import
java.util.properties;
import
study.javaenhance.advice;
public
class
beanfactory
{
private
properties properties =
new
properties();
public
beanfactory(inputstream instream)
{
try
{
properties.load(instream);
}
catch
(ioexception e)
{
e.printstacktrace();
}
finally
{
if
(instream !=
null
)
{
try
{
instream.close();
}
catch
(ioexception e)
{
e.printstacktrace();
}
}
}
}
public
object getbean(string name)
{
string classname = properties.getproperty(name);
object bean =
null
;
try
{
class
clazz =
class
.forname(classname);
bean = clazz.newinstance();
if
(bean
instanceof
proxyfactorybean)
{
proxyfactorybean proxybean = (proxyfactorybean) bean;
advice advice = (advice)
class
.forname(properties.getproperty(name +
".advice"
)).newinstance();
object target =
class
.forname(properties.getproperty(name +
".target"
)).newinstance();
proxybean.setadvice(advice);
proxybean.settarget(target);
object proxy = proxybean.getproxy();
return
proxy;
}
}
catch
(exception e)
{
// todo auto-generated catch block
e.printstacktrace();
}
return
bean;
}
}
|
如果这个类中包含proxyfactorybean,则调用proxyfactorybean中的getproxy方法。动态生成代理类。 proxyfactorybean.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
package
study.javaenhance.aopframework;
import
java.lang.reflect.invocationhandler;
import
java.lang.reflect.method;
import
java.lang.reflect.proxy;
import
study.javaenhance.advice;
public
class
proxyfactorybean
{
private
object target;
private
advice advice;
public
object gettarget() {
return
target;
}
public
void
settarget(object target) {
this
.target = target;
}
public
advice getadvice() {
return
advice;
}
public
void
setadvice(advice advice) {
this
.advice = advice;
}
public
object getproxy()
{
object object = proxy.newproxyinstance(target.getclass().getclassloader(),target.getclass().getinterfaces(),
new
invocationhandler()
{
@override
public
object invoke(object proxy, method method, object[] args)
throws
throwable {
advice.beforemethod(method);
object retvalue = method.invoke(target, args);
advice.aftermethod(method);
return
retvalue;
}
});
return
object;
}
}
|
接下来创建一个config.properties文件.config.properties 。
xxx=java.util.arraylist #xxx=study.javaenhance.aopframework.proxyfactorybean xxx.advice=study.javaenhance.myadvice xxx.target=java.util.arraylist 。
最后建立测试类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package
study.javaenhance.aopframework;
import
java.io.inputstream;
import
java.util.collection;
public
class
aopframeworktest
{
public
static
void
main(string[] args)
{
inputstream ips = aopframeworktest.
class
.getresourceasstream(
"config.properties"
);
object bean =
new
beanfactory(ips).getbean(
"xxx"
);
system.out.println(bean.getclass().getname());
((collection)bean).clear();
}
}
|
测试ok 。
总结:整个java增强的视频学习完成了,一共记住了多少我也不知道.但知道了很多内在的知识,如果有时间的话,或者说过一段时间可以拿出来问下,提供自己的技能.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://www.cnblogs.com/pony1223/p/7719766.html 。
最后此篇关于JAVA提高第八篇 动态代理技术的文章就讲到这里了,如果你想了解更多关于JAVA提高第八篇 动态代理技术的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在 JavaScript 中,我们可以动态创建 元素并附加到 部分,以便为大量元素应用 CSS 规则。 这种方法的优点或缺点是什么? 如果它确实提供了与元素上的 javascript 迭代相比的性
我有这个代码 import "./HTTPMethod.dart"; import '../../DataModel/DataModel.dart'; mixin RouterMixin { HT
哪些 OLAP 工具支持动态、动态地创建维度或层次结构? 例如,层次结构将成员定义为:“前 5 名”、“前 6-10 名”、“其他”... 计算成员是通常的答案,我正在寻找不同的东西。计算器的问题。成
我正在 CakePHP 中创建一个“表单编辑器”。 该界面允许用户选择要应用于字段的验证,例如数字、电子邮件等 因此,我需要根据用户输入为模型动态创建验证。为此,我可以使用验证对象:https://b
这是一个场景: 我有一个Web服务,我们将其称为部署在tomcat(轴)上的StockQuoteService。通过此 Web 服务公开了 getStockQuote() 方法。 现在,我想构建一个
我正在尝试从服务器获取 JSON 响应并将其输出到控制台。 Future login() async { var response = await http.get( Uri.
我从另一个问题中得到了这段代码(感谢 chunhunghan)。我需要创建一个登录屏幕,并尝试根据服务器发回给我的响应来验证用户凭据,但是每次我尝试运行代码时,它都会给我“未处理的异常:Interna
当我在“Dart”主程序中运行它时,一切正常,并且我得到了一个与会者列表。但是,当我在我的 Flutter 应用程序中调用它时,出现错误: flutter:“List”类型不是“List>”类型的子类
本文实例为大家分享了js实现验证码动态干扰的具体代码,供大家参考,具体内容如下 效果一 效果二 代码一 ?
目前我正在为我的网站使用 No-Ip,我想使用 cloudflare 来抵御 ddos 和机器人程序。我注意到您需要一个用于 cloudflare 的域。我还搜索了网络,发现了一个叫做 cloud
有没有办法在 Excel VBA 中构建动态 if 语句?基本上我正在尝试创建一个参数化计算,用户将能够输入不同的变量,即 变量 1 “变量 2” “变量 3” 在这种情况下 变量 1 是单元格引用
大家好, 请查看上面的图片,我有两张 table 。在下面代码的第一个表中,我得到了这种格式。 但我想像 Table2 那样格式化,每个合并单元格中的行数是动态的,而且不一样。 有没有办法像table
如何根据我添加的 View 修改标题部分的高度?heightForHeaderInSection在 viewForHeaderInSection 之前被调用我不知道 View 大小,直到我创建它。 最
是否存在在运行时生成 AST/解析树的解析器?有点像一个库,它会接受一串 EBNF 语法或类似的东西并吐出数据结构? 我知道 antlr、jlex 和他们的同类。他们生成可以做到这一点的源代码。 (喜
我在持有汽车制造商的表格上有一个 MultipleChoiceField。我想将我的汽车数据库过滤到已检查的品牌,但这会导致问题。如何动态获取所有 Q(make=...) 语句? 我如何开始:['va
$end = preg_replace($pattern, $replacement, $str); 如何使替换字符串 $replacement 随 $str 中的每次匹配而变化?例如,我想用关联的图
我正在编写一个 VBA 程序,用于过滤表中的值。我试图使其成为一个适用于您提供的所有表格的通用程序。在我的程序中,我必须设置它正在过滤的表的范围:Set rng = dataSheet.Range("
我正在循环一个元素数组,并且我想使用给定的模板递归地显示该元素 然后在该模板内使用带有切换功能的按钮来显示/隐藏给定元素的Child的更深级别模板(Child也是一个元素) 这是我的模板
从客户端(html)发送表单,服务器端通过选择选项之一决定运行哪个函数。 const decideWho = (form) => { const choice = form.choice; c
我有一个具有以下属性的按钮: circle_normal.xml(在 res/drawable 中) circle.xml(在 res/drawable 中)
我是一名优秀的程序员,十分优秀!