1、简介
1.1 代理是一个中间者的角色
它屏蔽了访问方和委托方之间的直接接触。也就是说访问方不能直接调用委托方的这个对象,而是必须实例化一个跟委托方有同样接口的代理方,通过这个代理方来完成对委托方的调用。访问方只和代理方打交道,这个代理方有点像掮客的角色,现实生活中的代理类似于中介机构。
1.2 什么时候需要用到代理模式呢?
- 访问方不想和委托方有直接接触,或者直接接触有困难。
- 访问方对委托方的访问需要增加额外的处理,例如访问前和访问后都做一些处理。这种情况下我们不能直接对委托方的方法进行修改,因为这样会违反“开闭原则”。
1.3 代理模式有两类:静态代理和动态代理,下面我们通过代码分别详细说明。
2、静态代理
静态代理的代理类每次都需要手动创建。
public interface Icar {
void move();
}
public class Benz implements Icar{
@Override
public void move() {
System.out.println("Benz move ...");
}
}
/**
* 静态代理
*/
public class BenzProxy implements Icar{
private Benz benz;
public BenzProxy() {
benz = new Benz();
}
@Override
public void move() {
//做一些前置工作 例如:检查车子的状况
System.out.println("检查车子的状况。。。");
benz.move();
//做一些后置工作 例如检查结果
System.out.println("车子2020-10-21号出厂,空调坏了。");
}
}
最后调用
public class ProxyMain {
public static void main(String[] args) {
BenzProxy benzProxy = new BenzProxy();
benzProxy.move();
}
}
3、 动态代理
动态代理的代理类可以根据委托类自动生成,而不需要像静态代理那样通过手动创建。动态代理类的代码不是在Java代码中定义的,而是在运行的时候动态生成的。这里主要用到InvocationHandler接口。
//动态代理类
public class CarHandler implements InvocationHandler {
//目标类的引用
private Object target;
public CarHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
//做一些前置工作 例如:检查车子的状况
before();
Object result = method.invoke(target, args);
//做一些后置工作 例如检查结果
after();
return result;
}
private void before() {
System.out.println("检查车子的状况。。。");
}
private void after() {
System.out.println("车子2019-10-1号出厂,空调坏了。");
}
}
调用动态代理:
public static void main(String[] args) {
ICar iCar = new Benz();
InvocationHandler handler = new CarHandler(iCar);
ICar proxy = (ICar) Proxy.newProxyInstance(ICar.class.getClassLoader(), new Class[]{ICar.class}, handler);
proxy.move();
}
4、 动态代理应用:简单工厂
接着上面动态代理调用方的使用方式,通过工厂模式加上泛型的方式,优化一下动态代理的生成和调用。
public class ProxyFactory {
private T client;//目标对象
private IBefore before;
private IAfter after;
public T createProxy(){
ClassLoader loader = client.getClass().getClassLoader();
Class>[] interfaces = client.getClass().getInterfaces();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if ("getName".equals(method.getName())){
//可根据name值过滤方法
}
//前置
if (before != null){
before.doBefore();
}
//执行目标对象的方法
Object result = method.invoke(client, objects);
//后置
if (after != null){
after.doAfter();
}
return result;
}
};
return (T) Proxy.newProxyInstance(loader,interfaces,handler);
}
public void setClient(T client) {
this.client = client;
}
public void setBefore(IBefore before) {
this.before = before;
}
public void setAfter(IAfter after) {
this.after = after;
}
}
创建前后置接口
public interface IAfter {
void doAfter();
}
public interface IBefore {
void doBefore();
}
使用和具体的产品业务分离出来了,方便维护和拓展:
public static void main(String[] args) {
//创建工厂
ProxyFactory factory = new ProxyFactory();
factory.setBefore(new IBefore() {
@Override
public void doBefore() {
System.out.println(" doBefore...");
}
});
factory.setClient(new Benz());
factory.setAfter(new IAfter() {
@Override
public void doAfter() {
System.out.println(" doAfter...");
}
});
//创建代理
ICar iCar = (ICar) factory.createProxy();
iCar.move();
}
5、 动态代理应用:AOP
AOP的英文全称是Aspect-Oriented Programming,即面向切面编程。AOP的实现方式之一是动态代理。
简单来说,AOP能够动态地将代码切入指定的位置,在指定位置上实现编程,从而达到动态改变原有代码的目的。
上面的IBefore和IAfter接口实际上就是简单地实现了AOP,例如在invoke具体方法之前和之后插入一些操作。
另外Proxy.newProxyInstance这个方法:
public static Object newProxyInstance(ClassLoader
loader,Class>[] interfaces,InvocationHandler h)
- loader:委托类的classLoader。
- interfaces:代理类需要实现的接口,这个接口同委托类的接口。
- h:调用处理器,只有一个invoke方法,调用委托类的任何方法都是通过它的invoke方法来完成的。