Java设计模式1:代理模式

代理模式(静态代理)
为其他对象提供一种代理以控制对这个对象的访问。对调用的业务方法作拦截、过滤、预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法,还可以规定调用后的操作。
 
静态代理示例:
1:首先定义一个接口,说明业务逻辑。  
 
public interface Subject {
    /**
     * static Proxy
     */
    void request();
}
 2:然后,定义业务实现类,实现业务逻辑接口
public class RealSuject implements Subject {
 
    @Override
    public void request() {
        System.out.println("*** static proxy do request !***");
    }
}
 
3:定义业务代理类
public class Proxy implements Subject {
 
    private Subject realSuject;//创建一个业务实现类对象来调用具体的业务方法
    
    public Proxy(Subject realSuject) {//构造器
        this.realSuject = realSuject;
    }
 
    @Override
    public void request() {
        System.out.println("预处理——————");//进行预处理操作
        if (realSuject != null) {
            realSuject.request();//调用真正的业务方法
        }
        System.out.println("结束处理——————");//进行调用后操作
    }
}
4:测试方法
private static void staticProxy() {
    RealSuject realSuject = new RealSuject();//先创建业务实现类对象
    Proxy proxy = new Proxy(realSuject);//把业务实现类对象作构造参数创建一个代理类对象
    proxy.request();//进行业务方法的调用
}
静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。
 
二:JDK动态代理
原理:
1:拿到被代理对象的引用,然后获取它的接口
2:JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
3:拿到被代理对象的引用
4:重新生成一个class字节码
5:然后编译
字节码重组 
 
JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象以及方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。我们需要做的,只需指定代理类的预处理、调用后操作即可。
1:首先,定义业务逻辑接口
public interface Subject {
   /**
    * dynamicProxy
    */
    public abstract void request();
}
2:然后,实现业务逻辑接口创建业务实现类
public class RealSujectImpl implements Subject {
 
    @Override
    public void request() {
        System.out.println("*** dynamicProxy  do request ***");
    }
 
}
3:采用JDK动态代理必须实现InvocationHandler接口,采用Proxy类创建相应的代理类 
public class SubjectInvocationHandler implements InvocationHandler {
 
    /**
     * 目标对象,用来调用具体的业务方法
     */
    private Object target;
 
    public SubjectInvocationHandler(Object target) {
        this.target = target;
    }
 
    /**
     * 包装调用方法:进行预处理、调用后处理  反射,这样你可以在不知道具体的类的情况下,根据配置的参数去调用一个类的方法。在灵活编程的时候非常有用。
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----Dynamic Proxy invoke method Start  ----");
        Object result = method.invoke(target, args);//方法调用
        System.out.println("----Dynamic Proxy invoke method End----");
        return result;
    }
 
    public Object getProxy() {
        //获取当前线程的 classloder
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        //获取所有的interface
        Class<?>[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }
}
4:测试
private static void dynamicProxy() {
    RealSujectImpl realSubject = new RealSujectImpl();//创建一个业务实现类对象
    SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);//创建一个代理类对象
    Subject subject = (Subject) handler.getProxy();//(向上转型)
    subject.request();//调用
}
JDK动态代理的代理对象在创建时,需要使用业务实现类所实现的接口作为参数(因为在后面代理方法时需要根据接口内的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。
三:CGlib动态代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。 
1:首先定义业务类,无需实现接口
public class RealSujectImpl2 {
 
    public void request() {
        System.out.println("*** dynamicProxy  do request ***");
    }
 
}
2:实现 MethodInterceptor方法代理接口,创建代理类,需要导入cglib.jar,然后使用Enhancer类与MethodInterceptor接口
public class SubjectCglib implements MethodInterceptor {
 
    private Object targerObj; //原对象
 
    //通过原对象返回代理对象
    public Object createInstance(Object targerObj) {
        this.targerObj = targerObj;
        Enhancer en = new Enhancer();
        return en.create(this.targerObj.getClass(), this.targerObj.getClass().getInterfaces(), this);
    }
 
    // 实现回调方法
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("用户验证...");
        Object result = methodProxy.invoke(targerObj, args);
        System.out.println("xx用户调用xx方法");
        return result;
    }
 
}
3:创建业务类和代理类对象,然后通过代理类对象.createInstance(业务类对象)返回一个动态代理类对象。最后通过动态代理类对象进行方法调用。
/**
* 动态代理
*/
private static void dynamicCglibProxy() {
    RealSujectImpl2 realSubject = new RealSujectImpl2();
    SubjectCglib cglib = new SubjectCglib();
    RealSujectImpl2 sujectCglib = (RealSujectImpl2)cglib.createInstance(realSubject);
    sujectCglib.request();
}
优点:
1、一个动态代理类更加简单了,可以解决创建多个静态代理的麻烦,避免不断的重复多余的代码
2、调用目标代码时,会在方法“运行时”动态的加入,决定你是什么类型,才调谁,灵活
缺点:
1、系统灵活了,但是相比而言,效率降低了,比静态代理慢一点
2、动态代理比静态代理在代码的可读性上差了一点,不太容易理解
3、JDK动态代理只能对实现了接口的类进行代理
静态代理VS动态代理,打成了平手,各自有各的独特之处,均不可代替,在项目中到底使用哪种代理,没有最好,只有更合适。
    
 
 

转载于:https://www.cnblogs.com/rachael/p/10176572.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值