设计模式之代理模式

代理模式

  • 作用:在不改变原有代码的基础上,增加或扩展额外的功能
  • 静态代理
//1,被代理类需要实现的接口,代理类也要实现该接口,该接口对用户使用
interface FlightMachine{
    void fly();
}
//2,被代理类实现接口
class FlightMachineImpl implements FlightMachine{

    @Override
    public void fly() {
        System.out.println("我可以飞");
    }
}
//3,代理类实现接口
class FlightProxy implements FlightMachine{
    //4,代理类引用被代理对象
    private FlightMachine flightMachine;

    //5,写有参构造方法得到被代理对象实例
    public FlightProxy(FlightMachine flightMachine){
        super();
        this.flightMachine=flightMachine;
    }

    @Override
    public void fly() {
        //增加额外的功能
        System.out.println("我可以发射导弹");
        flightMachine.fly();
        //增加额外的功能
        System.out.println("我可以航拍");
    }
}
public class TestProxy {
    public static void main(String[] args) {
        FlightMachine flightMachine = new FlightMachineImpl();
        FlightMachine flightProxy = new FlightProxy(flightMachine);
        flightProxy.fly();
    }
}

console:
我可以发射导弹
我可以飞
我可以航拍

小结:代理类和被代理类都需要实现同一个接口,且代理类预先设定,造成服务单一,要是其他类需要代理则需要更多代理类,不易扩展,缺点比较明显,适用场景不广。

  • 动态代理
    • JDK代理
      • 使用JDK自带的代理类,制造代理工厂
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//1,被代理类实现的接口
interface FlightMachine{
    void fly();
}
//2,被代理类需要至少实现的一个接口
class FlightMachineImpl implements FlightMachine{
    @Override
    public void fly() {
        System.out.println("我可以飞");
    }
}
//3,创建动态代理的工厂类,用来动态生成代理类对象
class FlightProxyFactory{
    //4,需要引用被代理的对象
    private Object target;

    //5,写有参构造方法得到代理目标实例
    public FlightProxyFactory(Object target) {
        this.target = target;
    }

    //6,提供一个获取代理类对象的方法
    public Object getProxyInstance(){
        //用JDK自带的reflect包的Proxy创建代理类实例
        /*
        @Proxy.newProxyInstance(Param1,Param2,Param3){ }
        参数1:类加载器,一般一个项目只有一个类加载器,所以选取比较方便获取的类来getClassLoader()就行
        参数2:代理目标所实现的所有接口,通过.getClass().getInterfaces()获得
        参数3:方法调用处理器
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), new InvocationHandler() {
                    /*
                    invoke(Param1,Param2,Param3){  }
                    参数1:代理类对象
                    参数2:被代理类(代理目标)需要执行的方法
                    参数3:执行方法需要的参数
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //增加额外的功能
                        System.out.println("我可以发射导弹");
                        //通过反射来调用代理目标方法
                        Object procedure = method.invoke(target, args);
                        //增加额外的功能
                        System.out.println("我可以航拍");
                        return procedure;
                    }
                });
    }

}

public class TestProxy {
    public static void main(String[] args) {
        FlightMachine flightMachine = new FlightMachineImpl();
        FlightProxyFactory flightProxyFactory = new FlightProxyFactory(flightMachine);
        Object proxyInstance = flightProxyFactory.getProxyInstance();
        if (proxyInstance instanceof FlightMachine){
            FlightMachine machineProxy = (FlightMachine) proxyInstance;
            machineProxy.fly();
        }
    }
}
console:
我可以发射导弹
我可以飞
我可以航拍

小结:建立代理工厂,根据需要的类动态生成代理类,虽然代理目标不固定,但是需要实现至少一个接口,不是所有的类都实现了接口或者继承了某个类,所以还不够好,但是JDK代理在反射生成代理类方面是作用较好,和其他动态代理方式配合使用效果更好。

  • CGLIB代理
    • 使用第三方代理包,cglib和asm两个包需要引入,核心接口是MethodInterceptor,核心类是Enhancer,给被代理类动态生成一个子类来进行代理(子类对父类来说就相当于扩展了功能)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


//1,被代理类
class FlightMachineImpl {
    public void fly() {
        System.out.println("我可以飞");
    }
}
//2,创建cglib动态代理的工厂类,用来动态生成代理类、代理类对象,并实现MethodInterceptor接口
class CglibProxyInterceptor implements MethodInterceptor {
    //3,引用代理目标的对象
    private Object target;

    //4,写有参构造方法得到代理目标实例
    public CglibProxyInterceptor(Object target) {
        this.target = target;
    }

    //5,提供一个获取代理类对象的方法
    public Object getProxyInstance(){
        //6,用cglib包的Enhancer创建代理类,且该代理类需要继承代理目标成为其子类
        Enhancer enhancer = new Enhancer();
        //7,将代理目标设置为代理类的父类
        enhancer.setSuperclass(target.getClass());
        //8,设置回调函数
        enhancer.setCallback(this);
        //9,创建代理类对象
        return enhancer.create();
    }
    //6,实现intercept方法
    /*
        @intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy){ }
        参数1 o:被代理的对象
        参数2 method:代理对象的方法,这里是FlightMachineImpl的fly()方法
        参数3 objects:方法的参数
        参数4 methodProxy:方法代理,这里代理的是cglib代理的fly()方法
         */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("我可以发射导弹");
        Object result = method.invoke(target, objects);
        System.out.println("我可以航拍");
        //methodProxy的invokeSuper可以实现相同的效果
//        Object result = methodProxy.invokeSuper(o, objects);
        return result;
    }
}

public class TestProxy {
    public static void main(String[] args) {
        CglibProxyInterceptor cglibProxyInterceptor = new CglibProxyInterceptor(new FlightMachineImpl());
        Object proxyInstance = cglibProxyInterceptor.getProxyInstance();
        if (proxyInstance instanceof FlightMachineImpl){
            FlightMachineImpl flightMachine = (FlightMachineImpl) proxyInstance;
            flightMachine.fly();
        }
    }
}
console:
我可以发射导弹
我可以飞
我可以航拍

小结:使用cglib代理,代理目标不用实现接口或继承类,只需根据该被代理类生成子类作为其代理类完成代理,和JDK代理一起在spring aop中使用广泛。


至此,若有纰漏,望各位不吝赐教