静态代理
package com.macro.mall.test;
/**
* 静态代理
*/
public class StaticProxy {
public static void main(String[] args) {
//创建一个代理对象
ICarFactory iCarFactory = new CarProxy();
//代理对象调用sellCar方法,而在代理对象的sellCar方法中则调用了生产厂商的卖车服务向用户提供了汽车
iCarFactory.sellCar();
}
}
/**
* 一个卖车的功能抽象成接口
*/
interface ICarFactory {
public void sellCar();
}
/**
* 车辆厂家,实现卖车的接口
*/
class CarFactory implements ICarFactory {
@Override
public void sellCar() {
System.out.println("我是车辆厂家,这是我对卖车接口的实现");
}
}
/**
* 这是一个车辆的代理商,也实现了卖车的接口
*/
class CarProxy implements ICarFactory {
//最后提供卖车服务的目标对象
private ICarFactory target;
@Override
public void sellCar() {
if (target == null) {//如果没初始化,new一下车辆的生产厂商
target = new CarFactory();
}
target.sellCar();//调用生产厂商的卖车实现
}
}
静态代理中三个角色的含义:
1.抽象角色: 真实角色和代理角色的共同接口,上述例子中的ICarFactory ,汽车生产厂商和代理厂商都需要实现该接口并实现接口中的方法。
2.真是角色: 最重要引用的对象,上述例子中的厂商实现类CarFatory,会提供真是的服务。
3.代理角色:内部含有真实对象的引用,从而可以操作真实对象,上述例子中的代理商类CarProxy,在其中引入真实角色,并且调用真实角色中的方法向用户提供服务。
动态代理
package com.macro.mall.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
/**
* 要被代理的真实对象
*/
IService iService = new ServiceImpl();
/**
* 要代理那个真实对象就输入进去这个真实对象
*
*/
InvocationHandler invocationHandler = new MyInvocationHandler(iService);
/**
* 通过第一个参数指定加载代理对象的方法
* 通过第二个参数指定为代理对象提供服务的接口
* 通过第三个参数把整个代理对象关联到invocationHandler这个对象上
*/
IService serviceProxy = (IService) Proxy.newProxyInstance(iService.getClass().getClassLoader(),
iService.getClass().getInterfaces(), invocationHandler);
System.out.println(serviceProxy.sellCar("奔驰"));
}
}
/**
* 提供卖车服务的接口
*/
interface IService{
public String sellCar(String carName);
}
/**
* 实现服务的类
*/
class ServiceImpl implements IService{
@Override
public String sellCar(String carName) {
return carName;
}
}
/**
* 实现反射包中的InvocationHandler接口
*/
class MyInvocationHandler implements InvocationHandler {
private Object target;
//在构造函数中初始化target对象
MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Call:" + method.getName());
/**
* 通过method中的invoke方法调用target类中的方法
* args是参数。是从invoke方法的参数中输入的
*/
Object obj = method.invoke(target, args);
return obj;
}
}
通过上述代码,我们能看到动态代理中确实用到了代理机制,但是我们明明没有在main方法中调用MyInvocationHandler类的invoke方法,但是为什么输出结果显示还是被调用了?
这是因为MyInvocationHandler类实现了InvocationHandler接口,并且把代理对象和invocationHandler关联上了,根据invocationHandler的内部实现机制,如果地阿里类serviceProxy发出调用方法的请求,那么这个请求最终会在invoke方法中调用。
那么下一问题:既然serviceProxy也是Iservice类型的那么为什么不直接如下new,而是通过代理来调用?
IService serviceProxy = new ServiceImpl();
serviceProxy.sellCar();
与new方法不同,这里我们把调用控制权交给了InvocationHandler接口的invoke方法,换句话说,在调用sellCar方法时,这个调用请求会先被invoke方法截取,在处理sellCar方法的之前或之后,我们可以添加必要的代码。
例如我们要在sellCar方法之前添加一个选车的方法,在之后添加一个加入车友会的方法,如果不用动态代理,大概代码会如下:
调用选车方法
调用sellCar方法
调用加入车友会方法
如果代码中有100个调用sellCar的方法,那个就要修改100次,每一个的之前之后都加上这两个方法,很难维护,但是如果基于动态代理实现,只需要在invoke方法的这个地方加上两个方法就好了。
/**
* 实现反射包中的InvocationHandler接口
*/
class MyInvocationHandler implements InvocationHandler {
private Object target;
//在构造函数中初始化target对象
MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Call:" + method.getName());
/**
* 通过method中的invoke方法调用target类中的方法
* args是参数。是从invoke方法的参数中输入的
*/
//选车方法
Object obj = method.invoke(target, args);
//加入车友会方法
return obj;
}
}
总结:与静态代理相比,动态代理的有时就是真实服务里面的所有方法最终都是在InvocationHandler接口的invoke方法里被调用的。一方面,当接口方法数量比较多的时候,可以灵活的通过method.invoke的反射机制来处理,而不需要像静态代理那样定义很多用不上但不得不重写的方法(如果实现了接口,就必须重写方法,不管用不用得到),另一方面,在动态代理的invoke方法中,还可以在调用服务之前或之后等位置加上相关代码,这点静态代理也是无法轻易做到的。
网友评论