java基础——静态代理和动态代理

发布时间 2023-04-07 15:40:47作者: -涂涂-

java代理模式有静态代理和动态代理两种实现方式

一、静态代理

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

  优点:

    可以在不修改目标对象的前提下扩展目标对象的功能。
  缺点:
    冗余:由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
    不易维护:一旦接口增加方法,目标对象与代理对象都要进行修改。

 

  **静态代理的特点**

    1、目标角色固定

    2、在应用程序执行前就得到目标角色

    3、代理对象会增强目标对象的行为

    4、有可能存在多个代理 引起"类爆炸"(缺点)

 

二、动态代理

  动态代理利用了 JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。

  动态代理又被称为 JDK 代理或接口代理。静态代理与动态代理的区别主要在:

    1、静态代理在编译时就已经实现,编译完成后代理类是一个实际的 class 文件
    2、动态代理是在运行时动态生成的,即编译完成后没有实际的 class 文件,而是在运行时动态生成类字节码,并加载到 JVM 中
  注意:动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

  JDK 中生成代理对象主要涉及两个类,第一个类为 java.lang.reflect.Proxy,通过静态方法 newProxyInstance 生成代理对象,第二个为 java.lang.reflect.InvocationHandler 接口,通过 invoke 方法对业务进行增强

  **动态代理的特点**

    1、目标对象不固定

    2、在应用程序执行时动态创建目标对象

    3、代理对象会增强目标对象的行为

三、代码实例

  用代码模拟一下结婚和婚庆公司演示静态代理

// 定义一个接口结婚的接口
interface  Mary{
    void mary() ;
}

//每个人都要结婚
class You implements Mary{//真实角色

    @Override
    public void mary() {
        System.out.println("要结婚了,很开心...");
    }
}


//婚庆公司---代理角色
class WeddingCompany implements Mary{
    //声明一个接口Mary类型变量
    private Mary mary ;
    public WeddingCompany(Mary mary){ //形式参数是一个接口,需要接口实现类对象
        this.mary = mary ;
    }

    @Override
    public void mary() {
        //代理角色需要帮助真实角色完成一件 "结婚这件事情"
        System.out.println("结婚之前,需要布置婚礼现场....");
        mary.mary() ;
        System.out.println("结婚之后,给婚庆公司付尾款....");
    }
}

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

        //没有使用静态代理之前
        //接口多态或者是具体类new 具体类
        Mary mary = new You() ;
        mary.mary() ;
        System.out.println("-----------------------------------------");
        //使用静态代理
        You you = new You() ;
        //创建代理角色
        WeddingCompany weddingCompany = new WeddingCompany(you) ;
        weddingCompany.mary();
    }
}
输出结果:

要结婚了,很开心…
----------------------------------------- 结婚之前,需要布置婚礼现场… 要结婚了,很开心… 结婚之后,给婚庆公司付尾款…

  用代码模拟一下结婚和婚庆公司演示动态代理

  1、针对用户访问的数据接口

public interface UserDao {
    /**
     * 添加功能
     */
    void add() ;

    /**
     * 修改功能
     */
    void update() ;

    /**
     * 查询功能
     */
    void select() ;

    /**
     * 删除功能
     */
    void delete() ;
}

  2、针对用户数据访问接口的实现

public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("添加功能");
    }

    @Override
    public void update() {
        System.out.println("修改功能") ;
    }

    @Override
    public void select() {
        System.out.println("查询功能");
    }

    @Override
    public void delete() {
        System.out.println("删除功能");
    }
}

  3、版本2:对业务方法 add,update,select.delete进行增强

public class UserDaoImpl2 implements UserDao {
    @Override
    public void add() {
        System.out.println("权限校验") ;

        System.out.println("执行添加功能");

        System.out.println("产生日志文件");
    }

    @Override
    public void update() {
        System.out.println("权限校验") ;

        System.out.println("执行修改功能");

        System.out.println("产生日志文件");
    }

    @Override
    public void select() {

        System.out.println("权限校验") ;

        System.out.println("执行查询功能");

        System.out.println("产生日志文件");
    }

    @Override
    public void delete() {

        System.out.println("权限校验") ;

        System.out.println("执行删除功能");

        System.out.println("产生日志文件") ;
    }
}
/*Proxy类下边的方法newProxyInstance
*   public static Object newProxyInstance(ClassLoader loader,   参数1:实现的接口的类加载器
*                                       Class<?>[] interfaces,  参数2:基于接口的字节码文件对象数组
*                                       InvocationHandler h)    参数3:是接口InvocationHandler :代理的处理程序
*                                throws IllegalArgumentException

*                                                    参数3是一个接口:自定一个类实现这个接口
*                                                       重写这个接口中的invoke方法
*                                                Object invoke(Object proxy,Method method,Object[] args)throws Throwable
*/

 

  4、基于代理的处理程序

public class MyInvocation  implements InvocationHandler {

    //要针对谁产生代理: ud                 UserDao ud = new UserDaoImpl() ;
    private Object target ;  //因为代理角色可以是任意Java类型,所以用Object
    public MyInvocation(Object target){
        this.target = target ;
    }


    //方法的返回值就是代理对象
    @Override                           //就是我们的接口的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("权限校验") ;

        //调用接口的列表自己的方法:update(),delete(),add(),select()
        //当前实例--->真实角色
        Object obj = method.invoke(target, args); //代理角色产生

        System.out.println("产生日志文件");
        return obj;
    }
}

 

  5、测试类

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

        //接口多态:测试UserDao
        UserDao ud = new UserDaoImpl() ; //真实角色
        //版本1:现在需要对功能增强,这个代码不合适!
        ud.add();
        ud.update();
        ud.select();
        ud.delete();
        System.out.println("----------------------------------");

        UserDao ud2 = new UserDaoImpl2() ;
        ud2.add();
        ud2.update();
        ud2.select();
        ud2.delete();

        System.out.println("----------------Jdk动态代理------------------");

        //前提示需要一个接口:UserDao

        MyInvocation handler = new MyInvocation(ud) ;
        // public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
        UserDao proxyInstance = (UserDao) Proxy.newProxyInstance(
                ud.getClass().getClassLoader(),
                ud.getClass().getInterfaces(),
                handler);
        proxyInstance.add();
        proxyInstance.update();
        proxyInstance.select();
        proxyInstance.delete();
    }
}

结果:

添加功能
​ 修改功能
​ 查询功能
​ 删除功能
​ ----------------------------------

​ 权限校验
​ 执行添加功能
​ 产生日志文件
​ 权限校验
​ 执行修改功能
​ 产生日志文件
​ 权限校验
​ 执行查询功能
​ 产生日志文件
​ 权限校验
​ 执行删除功能
​ 产生日志文件
​ ----------------Jdk动态代理------------------
​ 权限校验
​ 添加功能
​ 产生日志文件
​ 权限校验
​ 修改功能
​ 产生日志文件
​ 权限校验
​ 查询功能
​ 产生日志文件
​ 权限校验
​ 删除功能
​ 产生日志文件

 

 

参考:

https://blog.csdn.net/zjshuster/article/details/126439883

https://blog.csdn.net/longzorg_cn/article/details/129115728 

https://blog.csdn.net/m0_67499084/article/details/124810718