java-代理模式

2020-12-10  本文已影响0人  倔强青铜弟中弟

讲解内容:
1、代理模式
2、jdk动态代理
3、cglib动态代理

代理模式

(1)概念:

(2)设计模式

设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发者所采用的,它是开发中面临的一般问题的解决方案,这些解决方案是众多的软件开发人员经过相当长的实践的经验和错误总结出来的

(3)举例:

如果设计一个类,该类中含有加减乘除四个方法,现在需要给每一个类添加测试方法执行时间的代码,如果不适用代理类,就需要对每一个方法进行修改,需要修改多次。违背开闭原则(OCP,对扩展开放,修改关闭)和单一职责(SRP)。

(4)作用:

(5)实现方式:

静态代理

是在程序运行前就已经存在代理类的字节码文件,静态代理通常是对原有业务逻辑的扩充,通过让代理类持有真实对象,在代理类的源代码中调用被代理类方法来添加我们需要的业务逻辑。

例子:


(1)创建一个接口

interface Anmal{
    public abstract void show();
}

(2) 实现类

public class Fish implements Animal{

    @Override
    public void show() {
        System.out.println("我是鱼");
    }
}

(3)代理类:

public class ProxyFish implements Animal{

    Fish fish = new Fish();
    @Override
    public void show() {
        fish.show();
        System.out.println("我在游泳");
        //也可以写其他逻辑代码
    }
}

(4)测试类:

public class mainTest {
    public static void main(String arg[]) {
        ProxyFish proxyFish = new ProxyFish();
        proxyFish.show();
    }
}

缺点:如果有多个类需要代理,那么就需要创建多个代理类分别代理目标对象,工作量较大,不利于维护。可以结合工厂模式

动态代理:

动态代理是利用的反射机制动态地生成代理的对象,我们不需要知道谁代理谁。代理类的那部分代码被固定下来了,不会因为业务的增加而逐渐庞大

jdk动态代理

注意:jdk动态代理是要求实现类有接口。动手敲的时候别忘了写接口。cglib动态代理可以直接代理实现类,后面会有这两个对比

举例:

还是上面的案例,注意看代理类。
(1)创建一个接口:

interface Anmal{
    public abstract void show();
}

(2)实现类

public class Fish implements Animal{

    @Override
    public void show() {
        System.out.println("我是鱼");
    }
}

(3)实现代理类
这里为了让大家看清,代理类写到一个main方法里面了,后面会封装的。

public class mainTest {
    public static void main(String arg[]) {
        Animal objectProxy = (Animal)Proxy.newProxyInstance(//创建接口实例
                Animal.class.getClassLoader(),//用目标对象相同的类加载器动态代理运行时创建,将类加载到内存(反射)
                new Class[]{Animal.class}, // 被代理的类所实现的接口,可以是多个
                new InvocationHandler() {  // 绑定代理类的方法,将代理类和原有的实现类绑定,这里面要我们自己写代理类的逻辑功能
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("我是动态代理的鱼头");
                        method.invoke(new Fish(), args); // 执行目标对象的方法,就是原有实现类的方法。
                        System.out.println("我是动态代理的鱼尾");
                        //可以任写其他业务逻辑
                        return null;
                    }
                }
        );

        objectProxy.show(); // 调用代理类的方法
    }
}

(4)封装代理类:

public class FishProxy implements InvocationHandler {
    private Object object;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是动态代理的鱼头");
        Object result = method.invoke(object, args); // 执行目标对象的方法,就是原有实现类的方法。
        System.out.println("我是动态代理的鱼尾");
        return result;
    }

    public Object getFishProxy(Object targetObject){
        //为目标target赋值
        this.object = targetObject;
        //使用jdk动态代理,
        return Proxy.newProxyInstance(
                targetObject.getClass().getClassLoader(),//用目标对象相同的类加载器动态代理运行时创建,将类加载到内存(反射)
                targetObject.getClass().getInterfaces(), //被代理的类所实现的接口,可以是多个
                this //绑定代理类的方法,将代理类和原有的实现类绑定,这个类就是我们写的代理绑定方法,在invoke方法中
                );
    }
}

测试类:

public class mainTest {
    public static void main(String arg[]) {
//      Animal objectProxy = (Animal)Proxy.newProxyInstance(//创建接口实例
//              Animal.class.getClassLoader(),//用目标对象相同的类加载器动态代理运行时创建,将类加载到内存(反射)
//              new Class[]{Animal.class}, // 被代理的类所实现的接口,可以是多个
//              new InvocationHandler() {  // 绑定代理类的方法,将代理类和原有的实现类绑定,这里面要我们自己写代理类的逻辑功能
//                  @Override
//                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                      System.out.println("我是动态代理的鱼头");
//                      method.invoke(new Fish(), args); // 执行目标对象的方法,就是原有实现类的方法。
//                      System.out.println("我是动态代理的鱼尾");
//                      //可以任写其他业务逻辑
//                      return null;
//                  }
//              }
//      );
//
//      objectProxy.show(); // 调用代理类的方法
        FishProxy fishProxy = new FishProxy();
        Animal animal = (Animal) fishProxy.getFishProxy(new Fish());
        animal.show();
    }
}

JDK动态代理讲解:

invoke():
表示代理对象要执行的功能代码,你的代理类要完成的功能就写在invoke()方法中

(1)代理类要完成的功能:

(2)invoke方法:
invoke(Object proxy, Method method, Object[] args)

(3)使用过程:
1、invocationHandler接口:标识代理要干什么,定义目标代理类要完成的功能
2、创建目标类实现的接口
3、创建Invocationhandler接口的实现类,在invoke方法中完成代理类的功能书写。
method.invoke()方法用来执行目标方法的
4、使用Proxy.newProxyInstance静态方法,创建代理对象,代替new

Proxy.newProxyInstance需要三个参数:

cglib动态代理(cglib字节码增强)

举例:

还是上面的鱼例子,但是没有接口了
一个鱼的实现类

public class Fish {
    public void show() {
        System.out.println("我是鱼");
    }
}

cglib对鱼的代理类

public class FishCGProxy implements MethodInterceptor {
    Object object;
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        /**Object o: 
         * Method method: 被代理类中的方法 
         * Object[] objects: 
         * MethodProxy methodProxy:
         */
        System.out.println("我是动态代理的鱼头");
        Object result = method.invoke(object, objects); // 方法执行,参数:target 目标对象 arr参数数组
        System.out.println("我是动态代理的鱼尾");
        return result;
    }

    public Object getFishCGProxy(Object target){
        this.object = target;
        Enhancer enhancer = new Enhancer();
        //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this); // 设置回调

        return enhancer.create();//创建并返回代理对象
    }
}

总结:

(1)优缺点:

(2)概念:

在程序执行的过程中,使用jdk的反射机制,创建代理类对象并动态地指定要代理的目标类。也就是说动态代理是一种创建java对象的能力,使得我们不用创建淘宝类或微商类,就能创建代理类对象

(3)作用:

控制访问:在代理中,控制是否可以调用目标对象的方法

功能增强:可以在完成目标对象的调用时,附加一些额外的功能

代理方式:

(4)实现方式:

jdk动态代理:

使用java反射包中的类和接口实现动态代理的功能,反射包是java.lang.reflect,里面有三个类:InvocationHandler、Method、Proxy

cglib动态代理:

cglib是第三方的工具类

原理是继承,通过继承目标类创建它的子类,在子类中重写父类中的方法,实现功能的修改

要求目标类不能是final的,方法也不能是final的

对于没有接口的类,创建动态代理就要使用cglib

上一篇 下一篇

猜你喜欢

热点阅读