设计模式之代理模式

代理模式

代理模式又名 委托模式

作用:为其他对象提供一种代理以控制对这个对象的访问

通俗解释:对象A 想做一件事,让 代理对象B 代理,这件事就由 对象B 代替 对象A 做

本质:在原实例前后加一层处理(AOP的初级轮廓),实现增强

代理模式分为 静态代理 与 动态代理

静态代理

在程序运行前就已经存在代理类的字节码文件,代理类和原始类的关系在运行前就已经确定

现在有一个接口:用户的业务操作

public interface UserService {
    void add();
}

存在一个真实角色,即被代理对象:接口的实现类

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

如果这时候想要给业务方法添加日志功能,则需要修改每个方法

@Override
public void add() {
    System.out.println("使用了add方法");
    System.out.println("增加了一个用户");
}

如果现在有 n 个实现类,需要把所有东西都改一遍,代码量巨大,这种写法将浪费大量时间,且不合理

为了不改变原有代码而对方法进行增强,增加一个代理对象,并在其中维护一个真实角色

public class UserServiceProxy implements UserService {

    private UserServiceImpl userServiceImpl;

    public UserServiceProxy(UserServiceImpl userServiceImpl) {
        this.userServiceImpl = userServiceImpl;
    }

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

    //日志方法
    public void log(String msg) {
        System.out.println("使用了" + msg + "方法");
    }
}

创建一个真实对象,并创建一个代理对象,把真实对象托管给代理对象,让代理对象来执行方法

public static void main(String[] args) {
    // 0.创建一个真实角色
    UserServiceImpl userService = new UserServiceImpl();

    // 1.把真实对象交给代理对象管理,获得代理角色
    UserServiceProxy proxy = new UserServiceProxy(userService);
    proxy.add();
}

代理角色与真实角色要实现同一个接口

静态代理的优缺点

优点:

  • 静态代理使业务类只需要关心逻辑本身
  • 使真实角色的操作更加纯粹,不用关注一些公共的业务

缺点:

  • 一个真是角色,需要一个代理角色,编写的代码量大
  • 如果接口新添加一个方法,除了实现类需要实现这个方法之外,所有的代理类都要实现此方法,这种做法添加了代码的维护成本,解决方法为:使用动态代理

动态代理

在静态代理中,对于每个代理角色,都需要我们自动手写一个真实角色类,并对方法进行增强,而动态代理的代理类是动态生成的,其原理是利用 反射机制 完成

动态代理的实现:

  • JDK 动态代理:基于接口的动态代理
  • CGLIB 动态代理:没有接口的动态代理

这里主要讲解基于接口的 JDK 动态代理

主要步骤:使用 Proxy 的 newProxyInstance 方法获取代理类

代理对象和被代理对象要实现同一个接口,如果被代理对象没有实现任何接口,是无法为其创建代理对象的

newProxyInstance

Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  • ClassLoader loader:真实对象的类加载器
  • Class<?>[] interfaces:真实对象所实现的接口
  • InvocationHandler h:方法执行器,代理对象调用所有方法,都会执行该处理器,并对方法进行增强

具体实现

定义一个接口

public interface UserDao {
    int add(int a, int b);
}

现在接口有一个实现类

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

正常使用:

public class Demo {
    public static void main(String[] args) {
        final UserDao userDao = new UserDaoImpl();
        System.out.println(userDao.add(1, 2)); // 3
    }
}

执行结果:

3

使用动态代理实现日志的添加:通过 Proxy 类的 newProxyInstance 静态方法创建一个代理对象

public class Demo {
    
    public static void main(String[] args) {
        
        final UserDao userDao = new UserDaoImpl();
        
        // 通过 Proxy 类创建代理对象
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
           
                userDao.getClass().getClassLoader(), // 真实对象的类加载器
                userDao.getClass().getInterfaces(), // 真实对象所实现的接口
            	// 方法处理器,代理对象调用所有方法,都会执行该处理器,并对方法进行增强
                new InvocationHandler() { 

                    /**
                     * @param proxy 代理对象
                     * @param method 代理对象调用的方法
                     * @param args 方法传进来的参数
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    // invoke:增强方法
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        
                        // method.getName(): 获取调用方法名
                        // 通过方法名, 进行不同操作
                        if (method.getName().equals("add")) {
                            System.out.println("添加方法被执行了");
                            
                            int ans = (int)args[0] + (int)args[1];
                            
                            System.out.println("执行结果 " + args[0] 
                                               + " + " + args[1] + " = " + ans);
                            
                            Object result = method.invoke(userDao, args);
                            
                            System.out.println("方法执行完毕");
                            
                            // 利用反射执行目标方法
                            return result;
                        }
                        return null;
                    }
                }
        );
        userDaoProxy.add(1, 2);
    }
}

执行结果:

添加方法被执行了
执行结果 1 + 2 = 3
方法执行完毕

工具化:创建工厂,专门用来获取代理对象

public class UserProxyFactory {
    
    public static UserDao getProxy(final UserDao userDao) {
        
        Object o = Proxy.newProxyInstance(
                userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("add")) {
                            System.out.println("添加方法被执行了");
                            
                            int ans = (int) args[0] + (int) args[1];
                            System.out.println("执行结果 " + args[0] 
                                               + " + " + args[1] + " = " + ans);
                            
                            Object result = method.invoke(userDao, args);
                            System.out.println("方法执行完毕");
                            return result;
                        }
                        return null;
                    }
                }
        );
        return (UserDao) o;
    }
}

CGLIB

实现方式:以动态生成的子类继承目标的方式实现,在运行期动态的在内存中构建一个子类

使用前提:目标类不能为 final 修饰,因为 final 修饰的最终类不能被继承

public class UserDao{
    
}

CGLIB 是以动态生成的子类继承目标的方式实现,程序执行时,隐藏了下面的过程

public class $Cglib_Proxy_class  extends UserDao{
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值