美文网首页
AOP底层实现:JDK动态代理详解

AOP底层实现:JDK动态代理详解

作者: NisyCoding | 来源:发表于2020-06-10 21:08 被阅读0次

    一.创建代理的三要素:

    • 原始对象
    • 额外功能
    • 代理对象和原始对象实现相同的接口

    打个比方,我去卖房子,然后我要带客户去看房子;可是有一天,我不想每天都带那么多的客户去看房子,我该怎么办呢?找中介.让中介代替我,领着客户去看房子.那么中介需要伪装成是房东(此时就要重写原始对象中的方法).

    二.JDK动态代理:

    Proxy.newProxyInstance(classloader,interfaces,invocationHandler)
    

    2.1 invocationHandler介绍:

    2.1.1 MethodInterceptor拦截器回顾:

    我们在学习spring动态代理之MethodInterceptor拦截器的时候,需要实现MethodInterceptor接口,此时重写了接口中的invoke方法,invoke参数中有一个MethodInvocation,它此时代表额外功能增加的那个原始方法,代码如下:

    public class Arroud implements MethodInterceptor {
    
        /**
         * spring动态代理之MethodInterceptor拦截器
         * @param methodInvocation :额外功能增加的那个原始方法,如:register(),login()
         * @return: 因为每个方法的返回值都不一样,所以需要object类来接受
         * @throws Throwable
         */
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("额外功能----");
            //表示:该原始方法执行了,如register,login方法
            Object proceed = methodInvocation.proceed();
            System.out.println("方法的返回值:object="+proceed);
            return proceed;
        }
    }
    

    我们会发现,这个methodInvocation是被spring进行封装了的,但是我们的JDK的代理还是原生的.

    2.1.2 InvocationHandler介绍和演示:

    invocationHandler是一个接口.我们需要重写invoke方法,从而来增加额外的功能

    /**
             * 2.额外功能
             *
             *
             */
            final InvocationHandler invocationHandler=new InvocationHandler() {
                /**
                 * 为什么是method.invoke? 因为动态代理. 省去了service.register,service.login()
                 *
                 * @param proxy 代理对象
                 * @param method 原始对象的原始方法
                 * @param args  原始方法的参数
                 * @return   原始方法的返回值
                 * @throws Throwable
                 */
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //2.1 新增额外功能
                    System.out.println("jdk proxy...");
                    //2.2 执行原始对象的原始方法
                    Object invoke = method.invoke(userService, args);
                    return invoke;
                }
            };
    

    语法糖: jdk1.8之后,我们可以省略掉上面的final修饰符

    三. interfaces介绍:

    代理创建3要素的第三条,代理对象和原始对象需要实现相同的接口,这里的interfaces就是实现的接口.
    此时,我们怎么获取到这个接口呢?通过getClass().getInterfaces()可以获取到类的所有接口定义.

    四. classloader介绍:

    4.1 类加载器怎么获取呢?

    (1).我们知道,一个user.java文件,通过编译成user.class的字节码文件,这里每个类的class文件,自动会分配与之对应的classloader类加载器;
    (2).类加载器会把user.class字节码文件放入到JVM虚拟机中;
    (3).jvm虚拟机如何去创建一个user对象呢?此时肯定需要拿到user的class对象才能去创建user对象.此时也是通过类加载器去生成Class对象.

    此时,问题来了,我现在是动态代理呀,我拿不到具体的.java文件,我也没有具体的.class文件呀,顺其自然的,我也就没有对应的类加载器呀,我该怎么办?
    答: 去借一个

    五.最终的JDK动态代理代码如下:

    package com.baizhiedu.jdl;
    
    
    import com.baizhiedu.proxy.User;
    import com.baizhiedu.proxy.UserService;
    import com.baizhiedu.proxy.UserServiceImpl;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * JDK动态代理
     */
    public class TestJdkProxy {
    
        public static void main(String[] args) {
    
            //1.创建原始对象UserService
            final UserService userService = new UserServiceImpl();
    
    
            /**
             * 2.额外功能
             *
             *
             */
            final InvocationHandler invocationHandler=new InvocationHandler() {
                /**
                 * 为什么是method.invoke? 因为动态代理. 省去了service.register,service.login()
                 *
                 * @param proxy 代理对象
                 * @param method 原始对象的原始方法
                 * @param args  原始方法的参数
                 * @return   原始方法的返回值
                 * @throws Throwable
                 */
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //2.1 新增额外功能
                    System.out.println("jdk proxy...");
                    //2.2 执行原始对象的原始方法
                    Object invoke = method.invoke(userService, args);
                    return invoke;
                }
            };
    
            /**
             * 3.代理对象和原始对象实现相同的接口  interfaces:原始对象所实现的接口
             * 先借用userService的classLoader TestJdkProxy也可以
             */
    
            UserService service = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
            service.login(new User());
            service.register("Nisy",20);
        }
    }
    

    5.1 运行结果:

    jdk proxy...
    登录功能的核心代码...
    jdk proxy...
    注册功能的核心代码...
    

    相关文章

      网友评论

          本文标题:AOP底层实现:JDK动态代理详解

          本文链接:https://www.haomeiwen.com/subject/ztcmtktx.html