Spring 静态代理和动态代理

静态代理:

优点:

  1、  实现松散耦合。

  2、做到在不修改目标对象的功能前提下,对目标功能扩展。

缺点:

 如果项目中有多个类,则需要编写多个代理类,工作量大,不好修改,不好维护,不能应对变化。

模拟某位学生去考试作为例子:

下面创建 考试接口

public interface Examable {
    void exam();
}

创建Student学生实现这个考试接口(被代理)

public class Student implements Examable {
  
    @Override
    public void exam() {
        System.out.println("奋笔疾书,完成考题。。。");
    }

}

创键Cheater(代理)对象,同时也去实现Examable接口 

扫描二维码关注公众号,回复: 4558765 查看本文章
public class Cheater implements Examable {

  //被代理对象
private final Examable student; public Cheater(Examable student){ this.student=student; } @Override public void exam() { System.out.println("在现场唱了一首歌,差点被劝退"); student.exam();//调用Student类的方法 } }

测试:

public class Main {
//组合优于继承
public static void main(String[] args) {
//cheater 就是一个代理对象
//因为它是受student 委托,完成某个功能
//它要完成的主要功能,来自student
//除了委托做的事情,可能还会扩展一些行为


Examable xiaoming = new Student();//原来的行为
xiaoming.exam();

System.out.println("------下面是代理行为------");

Examable cheater = new Cheater(xiaoming);
cheater.exam();

}
}

结果:

奋笔疾书,完成考题。。。
------下面是代理行为------
在现场唱了一首歌,差点被劝退
奋笔疾书,完成考题。。。

动态代理:

使用JDK内置的Proxy实现

接着拿上面作为例子

下面创建 考试接口

public interface Examable {
    void exam();
}

创建Student学生实现这个考试接口(被代理)

public class Student implements Examable {
  
    @Override
    public void exam() {
        System.out.println("奋笔疾书,完成考题。。。");
    }

}

创建一个 JdkProxy 类 实现 InvocationHandler 接口

public class JdkProxy implements InvocationHandler {


    private Object object;//被代理

    public JdkProxy() {
    }

    public JdkProxy(Object object) {
        this.object = object;    ////初始化的时候就赋值
    }

    /**
     * 当用户调用对象中的每个方法时都通过下面的方法执行,方法必须在接口
     * proxy 被代理后的对象
     * method 将要被执行的方法信息(反射)
     * args 执行方法时需要的参数
     */


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        Object invoke = null;
        try {
            invoke = method.invoke(object, args);
        } catch (Exception e) {
            System.out.println("异常的信息" + e.getMessage());
        }
        return invoke;//调用被代理对象原来的方法(行为)
    }
}

测试:

 public class Main {

public static void main(String[] args) {
/*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数person1.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
         */


        ClassLoader cl= Thread.currentThread().getContextClassLoader();


        Examable o = (Examable) Proxy.newProxyInstance(
                cl,//类加载器
                new Class[]{Examable.class},//获取被代理对象的所有接口
                new JdkProxy(new Student())//InvocationHandler对象
        );
        o.exam();//代理后的行为

    }

}

结果:

使用内置的Proxy实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。

2、动态代理,使用cglib实现

还是拿上面的例子来说吧。

这次我们不写接口了。不过 我们要实现MethodInterceptor接口,并实现方法

去maven 中心仓库 找到 CGlib 的依赖

Student类

复制代码
public class Student {

    public void exam(){
        System.out.println("奋笔疾书,完成考试啦");
    }

}
复制代码

创建一个 CglibProxy 的类 并 实现  MethodInterceptor 接口 ,并实现方法

package com.nf147.sim.proxy.p5;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {


    /*
     * 参数
     * Object 为由CGLib动态生成的代理类实例
     * method 为上文中实体类所调用的被代理的方法引用
     * objects 为参数值列表
     * methodProxy 为生成的代理类对方法的代理引用
     * return 从代理实例的方法调用返回的值
     * */


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        return methodProxy.invokeSuper(o, objects);
    }
}

测试:

package com.nf147.sim.proxy.p5;


import com.nf147.sim.proxy.p1.Student;
import net.sf.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {

        //第一种方式


        //增强器,动态代码生成器
        Enhancer enhancer = new Enhancer();
        //设置 生成类 的 父类
        enhancer.setSuperclass(Student.class);
        //回调函数
        enhancer.setCallback(new CglibProxy());
        //动态生成字节码并返回代理对象
        Student o = (Student) enhancer.create();
        o.exam();

        System.out.println("-----------");

        //第二种方式
        //这里是简化写法
        //第一个参数 设置 生成类 的父类 ,第二参数 被代理类的所有接口 ,回调函数
        Student student = (Student) Enhancer.create(Student.class, null, new CglibProxy());
        student.exam();

    }
}

 结果:

猜你喜欢

转载自www.cnblogs.com/nongzihong/p/10139247.html