首页技术文章正文

Spring中的JDK动态代理是如何实现的?

更新时间:2021-05-25 来源:黑马程序员 浏览量:

1577370495235_学IT就到黑马程序员.gif

JDK动态代理是通过java.lang.reflect.Proxy 类来实现的,我们可以调用Proxy类的newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。

接下来,通过一个案例来演示Spring中JDK动态代理的实现过程,具体步骤如下。

(1)创建一个名为chapter03的Web项目,导入Spring框架所需JAR包到项目的lib目录中,并发布到类路径下。

(2)在src目录下,创建一个com.itheima.jdk包,在该包下创建接口UserDao,并在该接口中编写添加和删除的方法,如文件1所示。

文件1 UserDao.java

     package com.itheima.jdk;
     public interface UserDao {
        public void addUser();
         public void deleteUser();
     }

(3)在com.itheima.jdk包中,创建UserDao接口的实现类UserDaoImpl,分别实现接口中的方法,并在每个方法中添加一条输出语句,如文件2所示。

文件2 UserDaoImpl.java

     package com.itheima.jdk;
     // 目标类
     public class UserDaoImpl implements UserDao {
         public void addUser() {
             System.out.println("添加用户");
         }
         public void deleteUser() {
             System.out.println("删除用户");
         }
     }

需要注意的是,本案例中会将实现类UserDaoImpl作为目标类,对其中的方法进行增强处理。

(4)在src目录下,创建一个com.itheima.aspect包,并在该包下创建切面类MyAspect,在该类中定义一个模拟权限检查的方法和一个模拟记录日志的方法,这两个方法就表示切面中的通知,如文件3所示。

文件3 MyAspect.java

     package com.itheima.aspect;
     //切面类:可以存在多个通知Advice(即增强的方法)
     public class MyAspect {
         public void check_Permissions(){
             System.out.println("模拟检查权限...");
         }
         public void log(){
             System.out.println("模拟记录日志...");
         }
     }

(5)在com.itheima.jdk包下,创建代理类JdkProxy,该类需要实现InvocationHandler接口,并编写代理方法。在代理方法中,需要通过Proxy类实现动态代理,如文件4所示。

文件4 JdkProxy.java

     package com.itheima.jdk;
     import java.lang.reflect.InvocationHandler;
     import java.lang.reflect.Method;
     import java.lang.reflect.Proxy;
     import com.itheima.aspect.MyAspect;
     /**
      * JDK代理类
      */
     public class JdkProxy implements InvocationHandler{
         // 声明目标类接口
         private UserDao userDao;
         // 创建代理方法
         public  Object createProxy(UserDao userDao) {
             this.userDao = userDao;
             // 1.类加载器
             ClassLoader classLoader = JdkProxy.class.getClassLoader();
             // 2.被代理对象实现的所有接口
             Class[] clazz = userDao.getClass().getInterfaces();
             // 3.使用代理类,进行增强,返回的是代理后的对象
             return  Proxy.newProxyInstance(classLoader,clazz,this);
         }
         /*
          * 所有动态代理类的方法调用,都会交由invoke()方法去处理
          * proxy 被代理后的对象 
          * method 将要被执行的方法信息(反射) 
          * args 执行方法时需要的参数
          */
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) 
                                                                     throws Throwable {
             // 声明切面
             MyAspect myAspect = new MyAspect();
             // 前增强
             myAspect.check_Permissions();
             // 在目标类上调用方法,并传入参数
             Object obj = method.invoke(userDao, args);
             // 后增强
             myAspect.log();
             return obj;
         }
     }

在文件4中,JdkProxy类实现了InvocationHandler接口,并实现了接口中的invoke()方法,所有动态代理类所调用的方法都会交由该方法处理。在创建的代理方法createProxy()中,使用了Proxy类的newProxyInstance()方法来创建代理对象。newProxyInstance()方法中包含三个参数,其中第1个参数是当前类的类加载器,第2个参数表示的是被代理对象实现的所有接口,第3个参数this代表的就是代理类JdkProxy本身。在invoke()方法中,目标类方法执行的前后,会分别执行切面类中的check_Permissions()方法和log()方法。

(6)在com.itheima.jdk包中,创建测试类JdkTest。在该类中的main()方法中创建代理对象和目标对象,然后从代理对象中获得对目标对象userDao增强后的对象,最后调用该对象中的添加和删除方法,如文件5所示。

文件5 JdkTest.java

     package com.itheima.jdk;
     public class JdkTest{
         public static void main(String[] args) {
             // 创建代理对象
             JdkProxy jdkProxy = new JdkProxy();
              // 创建目标对象
             UserDao userDao= new UserDaoImpl();
             // 从代理对象中获取增强后的目标对象
             UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
             // 执行方法
             userDao1.addUser();
             userDao1.deleteUser();
         }
     }

执行程序后,控制台的输出结果如图1所示。

JDK动态代理

图1 运行结果

从图1可以看出,userDao实例中的添加用户和删除用户的方法已被成功调用,并且在调用前后分别增加了检查权限和记录日志的功能。这种实现了接口的代理方式,就是Spring中的JDK动态代理。





猜你喜欢:

JDK环境变量配置win10视频教程【黑马程序员】

两种常用的动态代理方式

一文详解Proxy动态代理的内部机制

jdk14视频教程:jdk14详细介绍

黑马程序员Java培训培训

分享到:
在线咨询 我要报名
和我们在线交谈!