什么是静态代理和动态代理,两者的区别(笔记)

1.什么是代理?

​ 代理: 就是让代理角色帮助真实角色完成一件事情;

​ 举例:过年回家让朋友代买火车票,朋友帮你买火车票的过程就是代理

2.静态代理

​ 什么是静态代理:

静态代理相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理还是原生的处理逻辑,不过在前后添加上需要添加的代码。
缺点:需要为每一个被代理的对象都创建一个代理类。

​ 特点:

​ 代理角色和真实角色都需要实现同一个接口,

​ 真实角色专注于自己的事情,

​ 代理角色目的就是帮助真实角色完成一件事情

​ 多线程的实现方式2:实现一个接口Runnable 使用的就是"静态代理"的思想

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

代码:

// 定义一个接口结婚的接口
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();
    }
}

输出结果:

要结婚了,很开心…

-----------------------------------------

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

3.动态代理

什么是动态代理?

Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例; 动态代理是通过 Proxy 创建代理对象,然后将接口方法“代理”给 InvocationHandler 完成的。

代码:

针对用户访问的数据接口

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

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

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

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

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

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("删除功能");
    }
}

版本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
*        public static Object newProxyInstance(ClassLoader loader,   参数1:实现的接口的类加载器
*                                       Class<?>[] interfaces,       参数2:基于接口的字节码文件对象数组
*                                       InvocationHandler h)         参数3:是接口InvocationHandler :代理的处理程序
*                                throws IllegalArgumentException

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

基于代理的处理程序

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;
    }
}

测试类:

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动态代理------------------
​ 权限校验
​ 添加功能
​ 产生日志文件
​ 权限校验
​ 修改功能
​ 产生日志文件
​ 权限校验
​ 查询功能
​ 产生日志文件
​ 权限校验
​ 删除功能
​ 产生日志文件

4.总结:

​ 静态代理总结:
1)代理类的信息在jvm运⾏之前就已经⽣成,逻辑由开发者实现;
2)代理类与⽬标类的定义应该严格参照规范,定义公共接⼝并实现它,需要代理的⽅法在接⼝中都要定义好;

静态代理原理:在代理类中包含⼀个⽬标类的对象引⽤,然后在使⽤时创建⼀个⽬标类对象并且创建⼀个代理类对象,并把⽬标类对象传给代
理类对象,然后将它赋予代理类中的⽬标类对象引⽤,然后代理类所代理的⽅法中通过其所包含的⽬标类对象引⽤调⽤⽬标类的⽅法,从⽽实现通过代理调⽤⽬标类⽅法的效果。

​ 动态代理总结:
1) 动态代理是指 在java程序运⾏过程(程序已经启动在运⾏了)由jvm⽣成代理类的class信息,该class信息⽣成后是直接处于内存中的,并没有写⼊磁盘保存起来;然后通过反射⽅式实例化代理类对象,因为代理类的class信息已经存在于内存中,所以可以通过反射⽅式实例化。
这个应该怎么理解呢?
​ 可以跟上⾯讲过的静态代理对⽐下,静态代理是需要开发⼈员⾃⼰实现代理类的逻辑的,且代理类的class信息是在程序运⾏之前就已经可以获取到的.java⽂件经过编译后可以得到.class⽂件;
​ ⽽动态代理是不需要开发⼈员⾃⼰实现代理类的,也就是说使⽤动态代理⽅式的话,项⽬代码中是不存在代理类的.java⽂件的,既然代理类未由开发者实现,那么程序经过编译之后肯定也不会有代理类的.class⽂件,
​ 也就是说经过编译之后程序未启动运⾏之前,关于代理类的信息我们⼀⽆所知,它是在程序运⾏过程中需要⽤到的时候才会由jvm动态⽣成的,⽽且⽣成之后也只存在于内存中,不会写到磁盘保存成.class⽂件,更加不会保存为.java⽂件;
​ 在程序重启或者说发⽣了gc,这个代理类的class信息从内存中被卸载之后,关于这个代理类的信息就没有了,只有当代码再次访问到代理对象时,才⼜会重新⽣成代理类的class信息。
2)动态代理与静态代理的区别是什么?
​ 上⾯已经讲述,不再赘述。
3)为什么需要引⼊动态代理?
​ 这就不得不说到静态代理的弊端,我们引⼊新事物,必定是因为旧事物存在不合理之处,所以才引⼊新的事物来弥补它的缺陷。
​ 那静态代理有什么缺陷呢?
​ 我们知道静态代理是需要开发者⾃⼰实现代理类逻辑的,也就是说要对某个类进⾏代理的话,需要实现这个类相应的代理类;
​ 如果⽬标类的数量很多的话,代理类的实现也必然得很多,可能会造成代码量过于庞⼤,可能会增加代码的冗余度…
​ 再者,如果⽬标类需要代理的⽅法很多的话,代理类需要对这些⽅法⼀⼀实现代理逻辑,代理类的实现也将会很庞⼤。

考虑到这些问题,催⽣了动态代理这种⽅式,它相⽐于静态代理来说,由于不需要开发者⾃⼰再实现代理类了,所以在实际⼤型项⽬中可能代码量会⼤⼤减少。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 静态代理是一种常见的设计模式,其主要思想是通过一个代理对象来控制对真实对象的访问,从而增强真实对象的功能或者限制对真实对象的访问。 静态代理的实现需要创建一个代理类和一个真实对象类,代理类和真实对象类都实现同一个接口或者继承同一个父类,代理类中持有真实对象的引用,在代理类的方法中调用真实对象的方法并对其进行增强或者限制。 静态代理的优点是实现简单,可以在不修改真实对象的情况下对其进行增强或者限制,缺点是需要为每一个真实对象类创建一个代理类,工作量较大。 下面是一个简单的静态代理示例: ```java public interface Subject { void request(); } public class RealSubject implements Subject { @Override public void request() { System.out.println("Real Subject Request"); } } public class ProxySubject implements Subject { private RealSubject realSubject; public ProxySubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { System.out.println("Before Real Subject Request"); realSubject.request(); System.out.println("After Real Subject Request"); } } public class Main { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); ProxySubject proxySubject = new ProxySubject(realSubject); proxySubject.request(); } } ``` 在上面的示例中,Subject 接口定义了一个 request 方法,RealSubject 类是真实对象类,实现了 Subject 接口的 request 方法,ProxySubject 类是代理类,也实现了 Subject 接口的 request 方法,在其方法中调用了 RealSubject 的 request 方法并对其进行了增强。 在 Main 类中,我们创建了一个 RealSubject 对象和一个 ProxySubject 对象,通过调用 proxySubject 的 request 方法,实际上是调用了它持有的 realSubject 的 request 方法,并对其进行了增强。 注意,在这个示例中,RealSubject 类和 ProxySubject 类都实现了 Subject 接口,这是静态代理的一种常见实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值