代理模式
静态代理
静态代理的模式有点点像适配器模式,但是适配器是实现用户端接口,而静态代理则是相反,它是去实现服务提供者(第三方库)的接口(ServiceInterface),实现相同的接口意味者代理(Proxy)和服务实现类(Service)有相同的方法,因此代理可以在方法中引用服务实现类中的相同方法,并在此基础上扩充自己的功能。这就相当于代理更像是服务实现类的扩充,符合开闭原则。
//服务接口
public interface Bank {
void getMoney(int money);
}
//服务
public class ATM implements Bank {
@Override
public void getMoney(int money) {
System.out.println("取钱:" + money + "元");
}
}
//代理
public class BankProxy implements Bank{
private Bank bank;
//聚合接口实现类
public BankProxy(Bank bank) {
this.bank = bank;
}
//方案2
public BankProxy() {
this.bank = new ATM();
}
//实现相同的方法
@Override
public void getMoney(int money) {
System.out.print("银行代理:");
bank.getMoney(money); //PS:这里需要自己调用,有隐患
System.out.println("扣除手续费:" + Float.valueOf(money) * 0.001 + "元");
}
}
//客户端
public class Client {
public static void main(String[] args) {
//附近找不到ATM,附近有便利店。便利店也是从ATM中取得钱。
//这里有点像是桥接模式(同一个接口算桥接吗?)
Bank proxy = new BankProxy(new ATM());
//也可以直接在代理类的构造方法直接初始化bank(方案2)
//Bank proxy = new BankProxy();
proxy.getMoney(10000);
}
}
通过上面的代码不难理解静态代理,但是静态代理有不足的地方。静态代理之所以是静态,是因为它的代理方法是直接写在代理类中的,需要人手动去调用实现类的方法(代码中有注释)。如果开发人员编程时不调用对应实现类的方法呢?如果方法名很相似,写错了呢?人是不可信的,所以就引出了动态代理,不需要认为去核对实现类和代理类的方法是否一致。
动态代理
动态代理是在内存中创建代理类的。动态代理能够使我们不写代理类,直接得到代理Class对象,然后根据它创建代理实例。动态代理的两种类型:JDK代理和Cglib代理。
JDK动态代理
JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合即可使用JDK动态代理。(代理目标需要有接口,没有接口则使用Cglib进行动态代理)
//接口方法
public interface Bank {
void getMoney(int money);
}
//代理目标类
public class ATM implements Bank {
@Override
public void getMoney(int money) {
System.out.println("取钱:" + money + "元");
}
}
//代理类工厂:负责创建不同目标类的代理类
public class ProxyFactory{
private Object obj;
/**
* 在工厂的构造方法中传入:目标类实例
* @param obj
*/
public ProxyFactory(Object obj) {
this.obj = obj;
}
//工厂类创建关于Bank的代理实例
public Object newBankProxyInstance(){
//使用Proxy的newProxyInstance方法
//参数:目标类启动器、目标类接口、代理方法的处理
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new InvocationHandler() {
//重写invoke方法,只要代理对象调用目标类的方法就会触发如下代码
@Override
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
System.out.println("代理类:" + proxy.getClass()
+ " 方法:" + method.getName()
+ " 参数:" + args.toString());
Object result = method.invoke(obj, args);
System.out.println("代理结束了");
return result;
}
});
}
}
public class Client {
public static void main(String[] args) {
Bank atm = new ATM();
//给工厂传入需要代理的接口类
ProxyFactory factory = new ProxyFactory(atm);
//使用工厂类创建一个代理对象
Bank bank = (Bank)factory.newBankProxyInstance();
//使用代理对象调用方法,会触发代理后的方法。
bank.getMoney(1000);
}
}
Cglib动态代理
使用Cglib进行代理,代理目标可以不需要实现接口。
PS:代理的类不能是final
代码如下
//代理目标类
public class ATM{
public void getMoney(int money) {
System.out.println("取钱:" + money + "元");
}
}
//代理类工厂
public class ProxyFactory {
private Object target;
public ProxyFactory(Object obj) {
this.target = obj;
}
public Object newProxyInstance(){
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj,
Method method,
Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("before method run...");
Object result = method.invoke(target, args);
System.out.println("after method run...");
return result;
}
});
//创建对象:代理对象
return enhancer.create();
}
}
//客户端调用
public class Client {
public static void main(String[] args) {
//代理目标对象
ATM atm = new ATM();
//传入目标对象
ProxyFactory factory = new ProxyFactory(atm);
//新建代理实例
ATM atmProxy = (ATM) factory.newProxyInstance();
//使用代理实例调用方法
atmProxy.getMoney(1000);
}
}