1
、代理模式
代理对象代表目标对象被访问,代理类
可以在目标对象实现的基础上,
增强额外的功能操作
,即扩展目标对象的功能。
2、
常见的三种代理实现
- 静态代理
- 动态代理
- java JDK代理
- Cglib代理
3、
静态代理
- 代理类和被代理类实现相同的接口或继承相同的父类,代理对象通过他们的共同的接口或父类访问被代理类。
- 实现:下面是问手机(YourPhone)的价格,但实际上是问华为手机的价格。
//公共接口:手机
publicinterface Phone{
publicvoid price();
}
//被代理类:华为
classHuaWei implements Phone{
@Override
publicvoid price() {
System.out.println("1000RMB");
}
}
//代理类
classYourPhone implements Phone{
HuaWeiphone; //必须要有被代理类的对象
publicYourPhone(HuaWei phone){
this.phone=phone;
}
@Override
publicvoid price() {
phone.price(); //实际是访问被代理类的价格
}
}
//测试代理
publicvoid testProxy(){
Phonep=newYourPhone(newHuaWei()); //代理对象
p.price(); //访问代理类的价格
}
- 优点:可以看到:在YourPhone类的price函数里加上其他功能,如:敬语。即添加额外功能。
- 缺点:每一个类都应要有一个代理类,即类数量增多了。接口一旦要更改,其实现类也需要更改。
4、java JDK动态代理
- 特点:代理类不需要实现共同接口或继承共同父类,直接通过JDK的API生成代理对象。
- 要动态创建代理对象需要用到InvocationHandler这个接口
//公共接口:手机
publicinterface Phone{
publicvoid price();
}
//被代理类:华为
classHuaWei implements Phone{
@Override
publicvoid price() {
System.out.println("1000RMB");
}
}
/*编写一个动态代理,不需实现接口,但需要制定接口。
* 值得注意的是,这可以代理不同的被代理类了*/
classProxyFactory{
Objectphone; //被代理类对象,不应指定某个代理类,让其动态绑定
publicProxyFactory(Object phone) {
this.phone=phone;
}
//h获取代理对象
publicObject getProxyInstance() {
//创建被代理类的事务处理器
InvocationHandlerih=newInvocationHandler() {
@Override
publicObject invoke(Object proxy, Methodmethod, Object[]args)throws Throwable {
returnmethod.invoke(phone,args);
}
};
/*
* phone.getClass().getClassLoader():被代理类的类加载器
* phone.getClass().getInterfaces():被代理类的接口
*/
returnProxy.newProxyInstance(phone.getClass().getClassLoader(),phone.getClass().getInterfaces(),ih);
}
}
//测试动态代理
publicvoid testProxy(){
Phonep=newHuaWei();//指定具体代理类
PhoneDProxy=(Phone)newProxyFactory(p).getProxyInstance(); //创建动态代理对象
DProxy.price();
}
5、
动态代理与静态代理的区别
- 上面说过,动态代理不用创建每一个代理类。即对于2个被代理类,静态代理需要创建2个代理类,而动态代理只需创建另一个动态代理对象即可。
- 下面增加apple手机的类,高亮的为新增代码
- 静态代理类:必须创建代理类Apple
//公共接口:手机
public
interface
Phone{
public
void
price();
}
//被代理类:华为
class
HuaWei
implements
Phone{
@Override
public
void
price() {
System.
out
.println(
"1000RMB"
);
}
}
//被代理类:苹果
class
Apple
implements
Phone{
@Override
public
void
price() {
System.
out
.println(
"5000RMB"
);
}
}
//代理类HuaWei
class
YourPhone
implements
Phone{
HuaWei
phone
;
//必须要有被代理类的对象
public
YourPhone(HuaWei
phone
){
this
.
phone
=
phone
;
}
@Override
public
void
price() {
phone
.price();
//实际是访问被代理类的价格
}
}
//代理类apple
class
YourPhone2
implements
Phone{
Apple
phone
;
//必须要有被代理类的对象
public
YourPhone2(Apple
phone
){
this
.
phone
=
phone
;
}
@Override
public
void
price() {
phone
.price();
//实际是访问被代理类的价格
}
}
//测试静态代理
public
void
testProxy2(){
Phone
p
=
new
YourPhone(
new
HuaWei());
//代理对象
Phone
p2
=
new
YourPhone2(
new
Apple());
p
.price();
//访问代理类的价格
p2
.price();
}
- 动态代理类:只需创建另一个代理对象
//公共接口:手机
public
interface
Phone{
public
void
price();
}
//被代理类:华为
class
HuaWei
implements
Phone{
@Override
public
void
price() {
System.
out
.println(
"1000RMB"
);
}
}
//被代理类:苹果
class
Apple
implements
Phone{
@Override
public
void
price() {
System.
out
.println(
"5000RMB"
);
}
}
/*编写一个动态代理,不需实现接口,但需要制定接口。
* 值得注意的是,这可以代理不同的被代理类了*/
class
ProxyFactory{
Object
phone
;
//被代理类对象,不应指定某个代理类,让其动态绑定
public
ProxyFactory(Object
phone
) {
this
.
phone
=
phone
;
}
//h获取代理对象
public
Object getProxyInstance() {
//创建被代理类的事务处理器
InvocationHandler
ih
=
new
InvocationHandler() {
@Override
public
Object invoke(Object
proxy
, Method
method
, Object[]
args
)
throws
Throwable {
return
method
.invoke(
phone
,
args
);
}
};
/*
* phone.getClass().getClassLoader():被代理类的类加载器
* phone.getClass().getInterfaces():被代理类的接口
*/
return
Proxy.
newProxyInstance
(
phone
.getClass().getClassLoader(),
phone
.getClass().getInterfaces(),
ih
);
}
}
//测试动态代理
public
void
testProxy(){
Phone
p
=
new
HuaWei();
//指定具体被代理类
Phone
DProxy
=(Phone)
new
ProxyFactory(
p
).getProxyInstance();
//创建动态代理对象
DProxy
.price();
Phone
p2
=
new
Apple();
Phone
DProxy2
=(Phone)
new
ProxyFactory(
p2
).getProxyInstance();
DProxy2
.price();
}
6、
Cglib代理
- Cglib代理也是动态代理,其与JDK代理不同的地方在于:JDK的被代理类需实现接口,而Cglib代理的被代理类不需实现接口。Cglib以被代理类的子类对象作为其代理类。
- 需下载底层包:Cglib-nodep 或其核心包Cglib-core
- 将下载的jar包导入项目:右键项目——Properties——Java Build Path,选Libraries选卡项,点击Add External JARs...。选择包导入后确认即可
- Cglib包的底层是通过使用一个字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
- 被代理的类不能为final,否则报错
- 被代理对象的方法如果为final/static,那么就不会被拦截,而是直接执行该方法.
//被代理类(需要注意的是,该类不能是内部类)
publicclass HuaWei {
publicvoid price() {
System.out.println(this+"1000RMB");
}
}
//另起一类
publicclass Cglib {
//Cglib代理
classProxyFactory2 implements MethodInterceptor{
Objectphone;
publicProxyFactory2(Object phone) {
this.phone=phone;
}
publicObject getProxyInstance() {
Enhancerenhance=newEnhancer(); //工具类
enhance.setSuperclass(phone.getClass()); //设置父类:被代理类
enhance.setCallback(this); //设置回调函数,这里的this是函数所在的类
//返回创建的子类:代理对象
returnenhance.create();
}
/**
* 执行被代理类的方法时拦截,并执行该方法
*@param
* obj:被代理类的对象
* method:被代理类的方法反射对象
* args:方法参数
* proxy:代理类对象
*/
@Override
publicObject intercept(Object obj, Methodmethod, Object[]args, MethodProxyproxy)throws Throwable {
returnmethod.invoke(phone,args);
//写法2
// proxy.invokeSuper(obj,args);
// return null;
}
}
//测试Cglib代理
publicvoid testProxy3() {
HuaWeihw=newHuaWei();
HuaWeiproxy=(HuaWei)newProxyFactory2(hw).getProxyInstance();
proxy.price();
}
publicstatic void main(String[] args) {
//TODO Auto-generated method stub
Cglibc=newCglib();
c.testProxy3();
}
}
- 程序分析:从testProxy3()函数开始,生成HuaWei类对象,这里我踩了一下坑:先前把这个类设置为内部类(原因不知道是什么,估计要看源码,望告知)。然后生成ProxyFactory2对象,主要是为了执行get类的getProxyInstance()方法,从而得到被代理类的子类:代理对象
- 该代理对象执行被代理类的方法时,都会被intercept 方法拦截(为了得到被代理对象)。