专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

JDK动态代理之实现与原理(一)【JDK篇】

一、代理概述

1. 概念

  • 代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

2. 分类

  • 代理分为 静态代理 和 动态代理(包括 JDK动态代理、CGLIB动态代理)。

3. 区别

  • 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件。
  • 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中。

二、JDK动态代理实现

1. JDK动态代理组成

  • 1)实现接口,被代理的对象必须实现某个或某些接口;
  • 2)拦截处理器,创建拦截处理器必须实现InvocationHandler接口并实现它的invoke方法;
  • 3)反射机制,调用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法,通过反射机制创建代理对象;

其中,Proxy.newProxyInstance方法的参数是loader–加载接口的类加载器、interfaces–代理类实现的接口列表、h–拦截处理器。拦截处理器可以持有被代理对象,当然特殊情况也可以不持有被代理对象,比如不需要调用被代理对象的方法。

2. JDK动态代理原理图

87_1.png

3. JDK动态代理实例

  • 创建接口 UserService
package com.java24k.example.service;

/**
 * @Description: 用户接口
 * @Author Java24K
 * @Date 2020/7/9 7:37 下午
 * @version: V1.0
 */
public interface UserService {

     /**
      * 增加用户
      * @author Java24K
      * @date 2020/7/9 7:38 下午
     */
    void addUser();

}

  • 创建接口实现 UserServiceImpl
package com.java24k.example.service.impl;

import com.java24k.example.service.UserService;

/**
 * @Description: 用户接口实现
 * @Author Java24K
 * @Date 2020/7/9 7:38 下午
 * @version: V1.0
 */
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("------增加一个用户------");
    }
}

  • 创建拦截处理器 UserInvocationHandler
package com.java24k.example.handler;

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

/**
 * @Description: JDK动态代理拦截处理器
 * @Author Java24K
 * @Date 2020/7/9 7:41 下午
 * @version: V1.0
 */
public class UserInvocationHandler implements InvocationHandler {

    /**
     *  真实对象 即被代理对象
     */
    private Object realSubject;

    public UserInvocationHandler(Object realSubject){
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("------插入前置通知代码------");
        // 执行被代理对象的目标方法
        Object result = method.invoke(realSubject, args);
        System.out.println("------插入后置处理代码------");
        return result;
    }
}

  • 组装创建动态代理
package com.java24k.example.test;

import com.java24k.example.handler.UserInvocationHandler;
import com.java24k.example.service.UserService;
import com.java24k.example.service.impl.UserServiceImpl;

import java.lang.reflect.Proxy;

/**
 * @Description: JDK动态代理测试类
 * @Author Java24K
 * @Date 2020/7/9 7:51 下午
 * @version: V1.0
 */
public class JDKProxyTest {

    public static void main(String[] args) {
        // 创建真实对象 即被代理对象
        UserService userService = new UserServiceImpl();
        // 创建拦截处理器
        UserInvocationHandler handler = new UserInvocationHandler(userService);
        // 创建jdk动态代理
        UserService jdkProxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),
                new Class[]{UserService.class}, handler);
        // 使用调用动态代理 调用方法
        jdkProxy.addUser();
    }
}

  • 运行结果
------插入前置通知代码-------------
---增加一个用户---
------插入后置处理代码-------------

Process finished with exit code 0

三、JDK动态代理优缺点

  • 缺点:不能实现接口的类就不能用JDK动态代理。因为生成的代理类继承了Proxy类后无法多继承,所以只支持接口。
  • 优点:java原生支持,不需要外部依赖。

四、JDK动态代理在框架中的运用

  • Mybatis运用动态代理实现xml的Mapper文件和Mapper接口的映射。 xml的namespace中有接口的全路径名,mybatis根据全路径名生成代理,当调用接口的方法,实际是调用代理的方法,然后进入拦截器invoke方法,根据sql的类型执行不同的语句。注意,这个Mybatis动态代理没有真实的代理对象。
  • Spring AOP 面向切面编程,就是使用代理在原方法前后做一些事情,即运行时增强,就用到JDK动态代理。

文章永久链接:https://tech.souyunku.com/19708

未经允许不得转载:搜云库技术团队 » JDK动态代理之实现与原理(一)【JDK篇】

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们