java静态代理和动态代理


参考: Java 动态代理详解

一、静态代理

实现静态代理分三步:

  1. 主题抽象类或者接口
  2. 真实对象实现接口方法
  3. 代理对象实现接口,代理主题

例子

假设要对一个service进行前后通知,先创建UserService主题接口

  1. 编写UserService主题
package com.yzx.proxy;

public interface UserService {

    void select();

    void update();

}
  1. 编写真实对象实现主题接口
package com.yzx.proxy;

public class UserServiceImpl implements UserService{
    @Override
    public void select() {
        System.out.println("查询数据");
    }

    @Override
    public void update() {
        System.out.println("更新数据");
    }
}

  1. 编写代理类对UserService进行增强
package com.yzx.proxy;

public class UserServiceProxy implements UserService{

    private UserService userService;

    public UserServiceProxy(UserService userService){
        this.userService = userService;
    }

    @Override
    public void select() {
        System.out.println("我要准备查询数据了");
        userService.select();
        System.out.println("查询数据完成");
    }

    @Override
    public void update() {
        System.out.println("我要准备更新数据了");
        userService.update();
        System.out.println("更新数据完成");
    }
}
  1. 客户端测试
package com.yzx.proxy;

public class Client01 {

    public static void main(String[] args) {
        UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl());
        proxy.select();
        proxy.update();
    }

}

输出
在这里插入图片描述
从结果可看出已经对真实对象进行了增强,并且对真实对象代码没有任何修改,这就是静态代理的一个好处。

但是仔细想想假如我要对多个类进行增强,使用静待代理解决的话有两种方式:

  1. 使用一个代理类、里面写多个接口,缺点是代理类会变的很庞大,里面接口过多。
  2. 使用多个代理类,每个代理类对一个类进行增强。缺点是代理类会很多。
    并且当主题接口要添加方法,删除方法时,代理类,真实对象类都要修改,这样维护会很麻烦。

要解决上面的问题就要使用到动态代理。

二、动态代理

两种常见的动态代理技实现:

  1. 通过实现接口的方式,JDK动态代理
  2. 通过继承的方式,CGLIB动态代理

1. JDK动态代理

jdk动态代理主要涉及到两个类:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

编写一个实现InvocationHandler调用逻辑处理器LogHandler类,提供日志增强功能;在LogHandler中维护一个目标对象;在invoke方法中编写调用方法的处理逻辑;

package com.yzx.proxy;

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

public class LogHandler implements InvocationHandler {

    Object object;

    public LogHandler(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(object, args);
        after();
        return result;
    }

    private void before(){
        System.out.println("前置通知");
    }

    private void after(){
        System.out.println("后置通知");
    }
}

编写客户端,获取动态生成的代理类的对象须使用Proxy的newProxyInstance方法,具体步骤可见代码和注释

import proxy.UserService;
import proxy.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client2 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        // 设置变量可以保存动态代理类,默认名称以 $Proxy0 格式命名
        // System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 1. 创建被代理的对象,UserService接口的实现类
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        // 2. 获取对应的 ClassLoader
        ClassLoader classLoader = userServiceImpl.getClass().getClassLoader();
        // 3. 获取所有接口的Class,这里的UserServiceImpl只实现了一个接口UserService,
        Class[] interfaces = userServiceImpl.getClass().getInterfaces();
        // 4. 创建一个将传给代理类的调用请求处理器,处理所有的代理对象上的方法调用
        //     这里创建的是一个自定义的日志处理器,须传入实际的执行对象 userServiceImpl
        InvocationHandler logHandler = new LogHandler(userServiceImpl);
        /*
		   5.根据上面提供的信息,创建代理对象 在这个过程中,
               a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等同的字节码
               b.然后根据相应的字节码转换成对应的class,
               c.然后调用newInstance()创建代理实例
		 */
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);
        // 调用代理的方法
        proxy.select();
        proxy.update();
        
        // 保存JDK动态代理生成的代理类,类名保存为 UserServiceProxy
        // ProxyUtils.generateClassFile(userServiceImpl.getClass(), "UserServiceProxy");
    }
}

输出结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值