java 静态代理 动态代理 学习

本文介绍了Java中的三种代理模式:无代理、静态代理和动态代理。无代理模式直接在业务代码上添加功能,不符合开闭原则;静态代理通过创建额外的代理类实现接口,避免修改原有代码;动态代理则利用Java反射机制,通过InvocationHandler动态生成代理对象,减少代码重复。动态代理在Spring AOP等框架中广泛应用,理解其原理对于框架学习至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.无代理模式

2.静态代理模式

3.动态代理模式

4.对动态代理我的理解 


1.无代理模式

代码结构:业务逻辑实现类UserServiceImpl 实现 UserService接口  客户端类Clint实现业务代码。

UserService接口

public interface UserService {

    void add();
    void delete();
    void update();
    void search();
}

UserServiceImpl类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {

        //新增功能
        System.out.println("《新增》  日志功能");

        //业务代码
        System.out.println("增加一个用户");
    }

    @Override
    public void delete() {

        //新增功能
        System.out.println("《新增》  日志功能");

        //业务代码
        System.out.println("删除一个用户");
    }

    @Override
    public void update() {

        //新增功能
        System.out.println("《新增》  日志功能");

        //业务代码
        System.out.println("更新一个用户");
    }

    @Override
    public void search() {

        //新增功能
        System.out.println("《新增》  日志功能");

        //业务代码
        System.out.println("查找一个用户");
    }

Client类

public class Client {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        //实现增加业务功能功能
        userService.add();
        //实现更新业务功能
        userService.update();
    }


}

运行结果

        分析:该种模式是在原有业务代码的基础上新增日志功能 ,修改原有业务代码是不好的,不符合aop中的开闭原则(不在已经实现的源代码上进行修改)。


2.静态代理模式

还是上面的代码

UserService接口

public interface UserService {

    void add();
    void delete();
    void update();
    void search();
}

UserServiceImpl类

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除一个用户");
    }

    @Override
    public void update() {
        System.out.println("更新一个用户");
    }

    @Override
    public void search() {
        System.out.println("查找一个用户");
    }

Proxy类

public class Proxy implements UserService{

    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }


    @Override
    public void add() {
        newLog();
        userService.add();
    }

    @Override
    public void delete() {
        newLog();
        userService.delete();
    }

    @Override
    public void update() {
        newLog();
        userService.update();
    }

    @Override
    public void search() {
        newLog();
        userService.search();
    }

    public void newLog(){
        System.out.println("<新增> 日志功能");
    }

Client类

public class Client {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        Proxy proxy = new Proxy();
        proxy.setUserService(userService);
        //实现增加业务功能功能
        proxy.add();
        //实现更新业务功能
        proxy.update();
    }

运行结果

           分析:不在原有已经写好的逻辑代码上更改,符合aop开闭原则 增加代理依赖业务类,实现与依赖的业务类一样的接口。在代理方法中调用原来业务方法在客户端中不直接调用业务实现类而是调用业务实现的代理例如上面例子中是调用Proxy类而不是业务实现类 。

        优点:满足了不修改源代码增加新的功能 。

        缺点:当需要增加新的功能时,每个接口的实现类都要写一个代理类代码量过大。


3.动态代理模式

UserService接口

public interface UserService {

    void add();
    void delete();
    void update();
    void search();
}

UserServiceImpl类

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除一个用户");
    }

    @Override
    public void update() {
        System.out.println("更新一个用户");
    }

    @Override
    public void search() {
        System.out.println("查找一个用户");
    }

自动生成代理类 MyInvocationHandler 类

package org.example.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成的到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //处理代理实例并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("---->"+proxy.getClass().getName());
        autoProxyLog(method.getName());
        //动态代理类的本质,就是使用反射机制
        Object result = method.invoke(target, args);
        return result;
    }

    public void autoProxyLog(String msg){
        System.out.println("调用了"+msg+"方法");
    }
}

Client类

 public static void main(String[] args) {
        //原业务方法
        UserService userService = new UserServiceImpl();

        //实例化自动生成代理的类
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        //注入要自动生成代理类的接口实现类(此代码中的 userService 对象)
        myInvocationHandler.setTarget(userService);

        //调用getProxy生成代理
        UserService userServiceProxy = (UserService) myInvocationHandler.getProxy();

        userServiceProxy.update();
        userServiceProxy.add();
        
    }

运行结果

        分析: 不在原有已经写好的逻辑代码上更改,符合aop开闭原则,增加代理依赖业务类,实现与依赖的业务类一样的接口,在代理方法中调用原来业务方法,在客户端中不直接调用业务实现类,而是调用业务实现的接口。

        优点:满足了不修改源代码增加新的功能,利用写好的 自动代理生成类(这里的 MyInvocationHandler) 自动生成统一接口实现类的的代理。

        缺点:理解困难。


对动态代理我的理解: 

        首先比较来学习,静态代理比较好理解,动态代理表面理解就是不用自己在手动反复的去创建代理,只需要我们自己写一个自动生成代理的类就可以用它来帮助我们生成代理。例如上面代码中的MyInvocationHandler类,该类就是用来帮助我们生成代理的一个类,该类生成的代理我在控制台中有打印代理的全名com.sun.proxy.$Proxy0。

        我的MyInvocationHandler类实现了InvocationHandler接口,该接口中只有一个invoke方法,该方法是实现动态代理的一个核心方法,该方法本质是利用反射。在该类中还实现了getProxy类,该类用来生成代理,就比如例子中生成的com.sun.proxy.$Proxy0类。该类中引用对象target是要实现代理的接口实现类(也就是我们例子中的UserServiceImpl类)。

        invoke方法中用方法的反射去实现Proxy中的方法,也就是我们的client中的proxy类实际调用的业务是invoke方法,调用该方法的类是通过反射proxy.getClass().getName()获取(获取的值:就是com.sun.proxy.$Proxy0),在这个Proxy0类中是怎么实现MyInvocationHandler中的invoke方法呢?简单理解就是在利用Proxy.newProxyInstance建造对象的的时候调用父类Proxy的构造器将InvocationHandler注入到$Proxy0中,$Proxy0中static静态代码块儿中利用反射初始化方法的名字,然后再具体的方法中利用注入的MyInvocationHandler的invoke来实现对应的方法。这一部分具体的代码可以参照--->动态代理 InvocationHandler中的invoke()方法是在哪被调用的_yjw19901214的博客-优快云博客_invocationhandler的invoke方法(这位博主写的十分详细,$Proxy0的代码也有源码可以参考,我也是参照这个才理解到这个invoke方法是怎么被Proxy类给实现的)。这部分主要的技术就是反射,看不懂的可以先去学习学习反射。

        动态代理在框架的运用中很多,例如Spring中的AOP就是个很常见的例子。所以还是很有学习的必要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值