代理(Proxy)模式

代理模式(Proxy Pattern),23个经典模式中的一个,又称之为委托模式,就是为目标对象提供了一个代理,这个代理可以控制对目标对象的访问。代理对象可以在被代理对象的基础上添加额外功能。
为什么要使用代理?
某人要找对象,但是由于某些原因(如工作太忙)不能直接去找,于是委托一个中介机构去完成这一过程,如婚姻介绍所,在这里婚姻介绍所就是一个代理,与此相类似的还有房屋中介、职业中介,它们充当的都是一个代理的角色。所谓代理,就是一个人或者一个机构代表另一个或者另一个机构采取行动。

静态代理

静态代理要求被代理类和代理类同时实现相应的一套接口,通过代理类调用重写接口的方法,实际上调用的是原始对象的同样的方法。
代码实现:

TargetInteface 接口

public interface TargetInteface {
    void method1();
    void method2();
    int method3(Integer i);
}

被代理类

public class Target implements TargetInteface {
    @Override
    public void method1() {
        System.out.println("method1 running ...");
    }

    @Override
    public void method2() {
        System.out.println("method2 running ...");
    }

    @Override
    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

代理类

public class TargetProxy implements TargetInteface {

    @Override
    public void method1() {
        System.out.println("执行方法前...");
        new Target().method1();
        System.out.println("执行方法后...");
    }

    @Override
    public void method2() {
        System.out.println("执行方法前...");
        new Target().method2();
        System.out.println("执行方法后...");
    }

    @Override
    public int method3(Integer i) {
        System.out.println("执行方法前...");
        int method3 = new Target().method3(i);
        System.out.println("执行方法后...");
        return method3;
    }
}

测试类

public class TargetUser {

    public static void main(String[] args) {
        TargetInteface target = new TargetProxy();
        target.method1();
        System.out.println("-----------------------------");
        target.method2();
        System.out.println("-----------------------------");
        System.out.println(target.method3(3));
    }
}

执行结果如下
在这里插入图片描述
静态代理还是比较容易理解的,代理类在执行被代理对象方法前后执行了打印操作,增强了功能。这便是代理模式的用途之一。

动态代理

假如一个类需要代理许多的对象,那么这个代理类将会同时实现许多个接口,这种办法不易被使用,所有就加入了新的代理模式—动态代理。
动态代理的代理类并不需要去实现各个接口,提供了一种新的代理形式。
动态代理有俩种实现方式:jdk代理和cglib代理
代码实现:
(1)jdk代理

TargetInteface 接口

public interface TargetInteface {
    void method1();
    void method2();
    int method3(Integer i);
}

被代理类

public class Target implements TargetInteface {
    @Override
    public void method1() {
        System.out.println("method1 running ...");
    }

    @Override
    public void method2() {
        System.out.println("method2 running ...");
    }

    @Override
    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

代理类

public class TargetProxy {
    public static  <T> Object getTarget(T t) {
        return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
                //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
                System.out.println("执行方法前...");
                Object invoke = method.invoke(t, args);
                System.out.println("执行方法后...");
                return invoke;
            }
        });
    }
}

测试类

public class TargetUser {

    public static void main(String[] args) {
        TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
        target.method1();
        System.out.println("-----------------------------");
        target.method2();
        System.out.println("-----------------------------");
        System.out.println(target.method3(3));
    }
}

结果如下
在这里插入图片描述
可以看到这个执行结果和上面哪一种是一样的。但是jdk代理代理类中并不需要去实现接口。而是采用了Proxy类的newProxyInstance()方法,仔细观察这个方法,可以看到方法参数内实现了一个匿名类,这是一个调用处理器。
调用处理器是实现了 InvocationHandler 接口的类对象,在这个接口中只有一个方法:
Object invoke(Object proxy, Method method, Object [] args)
无论何时调用代理对象的方法,调用处理器的 invoke 方法都会被调用, 并向其传递Method 对象和原始的调用参数。 调用处理器通过反射的形式调用被代理类的方法。

(2)cglib代理
cglib代理并不需要接口,而是采用类的方式去实现。可以说jdk代理是对实现接口的类的代理,而cglib代理是针对类的代理。
代码实现:
被代理类

public class Target {
    public void method1() {
        System.out.println("method1 running ...");
    }

    public void method2() {
        System.out.println("method2 running ...");
    }

    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

代理类

public class TargetProxy {

    static <T> Object getProxy(T t) {
        Enhancer en = new Enhancer(); //帮我们生成代理对象
        en.setSuperclass(t.getClass());//设置要代理的目标类
        en.setCallback(new MethodInterceptor() {//代理要做什么
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("执行方法前。。。");
                //调用原有方法  
                Object invoke = methodProxy.invokeSuper(object, args);
                // Object invoke = method.invoke(t, args);// 作用等同与上面。
                System.out.println("执行方法后。。。");
                return invoke;
            }
        });
        return en.create();
    }
}

测试类

public class TargetUser {

    public static void main(String[] args) {
        Target target = (Target) TargetProxy.getProxy(new Target());
        target.method1();
        target.method2();
        target.method3(1);
    }

}

执行结果
在这里插入图片描述
在代码中可以看出cglib代理与jdk代理不同之处在于是否有接口需要实现,并且cglib在代理实现的方式上也有所不同,cglib引用了Enhancer对象,通过Enhancer对象帮我们生成代理对象,用Enhancer的setCallback()方法执行被代理类的方法。
这里实现了MethodInterceptor接口,该接口中只有一个方法:
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
方法的调用会被转移到这个方法中执行。

总结一下cglib代理实现步骤:
Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值