JDK动态代理实现原理

  1. 静态代理模式我们不能满足开闭原则,其中的重复代码较多,且修改更新维护很不方便,我们想着能否不需要代理类直接生成代理对象,这样就可以解决一些静态代理的缺点

  2. 我们通过一个业务类和一个业务实现类来举例子代码如下:

    /**
     * 业务类
     *
     * @author Young Jun
     * @creat 2024-06-25-16:28
     */
    public interface IService {
        String eat();
    
        String sleep();
    }
    
    /**
     * @author Young Jun
     * @creat 2024-06-25-16:29
     * 业务实现类
     */
    public class IServiceImpl implements IService {
        @Override
        public String eat() {
            return "吃他个三大碗米饭";
        }
    
        @Override
        public String sleep() {
            return "睡他个自然醒";
        }
    }
    
  3. 我们现在想要动态的生成一个IServiceImpl的代理对象步骤如下:

    @Test
        public void test1() throws Exception /*这里异常我直接抛出了*/ {
            //目标对象
            IService service = new IServiceImpl();
            //通过getProxyClass()方法获取一个有IService.class信息且拥有构造器的Class类也就是代理对象的Class
            Class<?> proxyClass = Proxy.getProxyClass(service.getClass().getClassLoader(), service.getClass().getInterfaces());
            //通过代理对象的Class实例化通过构造器实例化(通过源码我们可以看到有一个有参构造器,其中的参数就是InvocationHandler)
            Constructor<?> constructor = proxyClass.getDeclaredConstructor(InvocationHandler.class);
            constructor.setAccessible(true);
            //传入参数(当然,可以用lambda表达式)(我们知道是IService所以可以强转)
            IService proxy =(IService) constructor.newInstance(new InvocationHandler() {
                //proxy代理对象
                //method代理方法
                //args 方法参数
                //这个方法就是用来给我做事的(它会拦截到代理对象执行方法,使其进入这个方法内)
                //这里面可以进行我们对目标方法的增强等一系列处理
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //比如我这里执行日志增强
                    System.out.println("日志前置增强");
                    //调用目标类的方法,这里就是反射的基础
                    // (其中需要两个参数,一个是目标类对象,另一个是方法参数,上面有了所以直接用)
                    Object result = method.invoke(service, args);
                    System.out.println("日志后置增强");
                    //返回方法执行结果
                    return result;
                }
            });
            System.out.println(proxy.eat());
            System.out.println(proxy.sleep());
        }
    //虽然解决了不需要代理类的问题,但是前置操作还是稍微烦锁了,且只能对一种接口的实现类进行加强
    //接下来我们就需要改进一下代码
    
    
  4. 创建一个ProxyUtil工具类简化代码

    public class ProxyUtil {
    
        /**
         *
         * @param target 目标类(为了避免局限性我们直接将其类设为Object)
         * @return 返回代理对象
         */
        public static Object getProxy(Object target) throws Exception {
            //通过getProxyClass()方法获取一个有IService.class信息且拥有构造器的Class类也就是代理对象的Class
            Class<?> proxyClass = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
            //通过代理对象的Class实例化通过构造器实例化(通过源码我们可以看到有一个有参构造器,其中的参数就是InvocationHandler)
            Constructor<?> constructor = proxyClass.getDeclaredConstructor(InvocationHandler.class);
            constructor.setAccessible(true);
            //传入参数(当然,可以用lambda表达式)
            Object proxy = constructor.newInstance(new InvocationHandler() {
                //proxy代理对象
                //method代理方法
                //args 方法参数
                //这个方法就是用来给我做事的(它会拦截到代理对象执行方法,使其进入这个方法内)
                //这里面可以进行我们对目标方法的增强等一系列处理
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //比如我这里执行日志增强
                    System.out.println("日志前置增强");
                    //调用目标类的方法,这里就是反射的基础
                    // (其中需要两个参数,一个是目标类对象,另一个是方法参数,上面有了所以直接用)
                    Object result = method.invoke(target, args);
                    System.out.println("日志后置增强");
                    //返回方法执行结果
                    return result;
                }
            });
            return proxy;
        }
    }
    
    
    
    //测试代码
    @Test
        public void test2() throws Exception /*这里异常我直接抛出了*/ {
            //目标对象
            IService service = new IServiceImpl();
            //通过getProxyClass()方法获取一个有IService.class信息且拥有构造器的Class类也就是代理对象的Class
            IService proxy =(IService) ProxyUtil.getProxy(service);
            
            System.out.println(proxy.eat());
            System.out.println(proxy.sleep());
        }
    //虽然解决了前置操作烦锁且不单单只能对一种接口的实现类进行加强,但是增强方法却只有一种,不符合实际,我可能有很多种增强的逻辑
    //接下来我们就需要再改进一下代码
    
  5. 改进一下getProxy()方法,我们自己定义InvocationHandler接口的实现类对象可以是匿名内部类也可以是自定义类实现InvocationHandler接口并重写invoke()方法

    /**
         *
         * @param target 目标类对象
         * @param handler 执行处理器,拦截方法得拦截器
         * @return 返回代理对象
         * @throws Exception
         */
        public static Object getProxy(Object target,InvocationHandler handler) throws Exception {
            //通过getProxyClass()方法获取一个有IService.class信息且拥有构造器的Class类也就是代理对象的Class
            Class<?> proxyClass = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
            //通过代理对象的Class实例化通过构造器实例化(通过源码我们可以看到有一个有参构造器,其中的参数就是InvocationHandler)
            Constructor<?> constructor = proxyClass.getDeclaredConstructor(InvocationHandler.class);
            constructor.setAccessible(true);
            //传入参数
            Object proxy = constructor.newInstance(handler);
            return proxy;
        }
    
    //测试代码
    @Test
        public void test3() throws Exception /*这里异常我直接抛出了*/ {
            //目标对象
            IService service = new IServiceImpl();
            //通过getProxyClass()方法获取一个有IService.class信息且拥有构造器的Class类也就是代理对象的Class
            IService proxy =(IService) ProxyUtil.getProxy(service, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //记录时间方法增强
                    System.out.println("记录开始时间...");
                    Object result = method.invoke(service,args);
                    System.out.println("记录结束时间时间...");
                    return result;
                }
            });
    
            System.out.println(proxy.eat());
            System.out.println(proxy.sleep());
        }
    
    //这样我们就可以自己自定义增强方法,更加灵活,但是我们感觉到getProxy()方法中的代码还是比较的繁琐,这个时候我们发现Proxy类中有一个静态方法newProxyInstance()
    
  6. 我们再次改造一下,使用现成的newProxyInstance()方法

    //现成的方法
    @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
     //ClassLoader loader类加载器,加载目标类的加载器
     //Class<?>[] interfaces 目标类的接口Class类
     //InvocationHandler h 执行处理器,拦截目标方法
            
     
    /**
         *
         * @param target 目标类对象
         * @param handler 执行处理器,拦截方法得拦截器
         * @return 返回代理对象
         * @throws Exception
         */
        public static Object getProxyWithProxyMethod(Object target,InvocationHandler handler) throws Exception {
            Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
            return proxy;
        }
    
    
    //测试代码
    
    @Test
        public void test4() throws Exception /*这里异常我直接抛出了*/ {
            //目标对象
            IService service = new IServiceImpl();
            //通过newProxyInstance()方法直接获取代理对象
            IService proxy =(IService) ProxyUtil.getProxyWithProxyMethod(service, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //对象属性增强
                    System.out.println("对象属性填充...");
                    Object result = method.invoke(service,args);
                    return result;
                }
            });
    
            System.out.println(proxy.eat());
            System.out.println(proxy.sleep());
        }
    
    //经过一系列的改进其实代码已经不错了,但是我们发现增强方法是硬编码,且总是匿名内部类会有重复代码重复代码,这时候又有的改了
    
  7. 利用面向对象思想讲增强方法封装到增强类中,且自定义一个InvocationHandler实现类

    1. 包结构如下:
  8. 在这里插入图片描述

    /**
     * @author Young Jun
     * @creat 2024-06-25-22:39
     * 事务增强类
     */
    public class TransactionAdvice {
    
        public void before(){
            System.out.println("开启事务...");
        }
    
        public void after(){
            System.out.println("提交事务...");
        }
    }
    
    /**
     * @author Young Jun
     * @creat 2024-06-25-22:41
     * 事务处理执行器
     */
    public class TransactionHandler implements InvocationHandler {
        //事务增强类
        private TransactionAdvice transactionAdvice;
        //目标对象
        private Object target;
    	//构造器注入属性
        public TransactionHandler(TransactionAdvice transactionAdvice, Object target) {
            this.transactionAdvice = transactionAdvice;
            this.target = target;
        }
        
    	//重写invoke方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //调用增强和目标方法
            transactionAdvice.before();
            Object result = method.invoke(target,args);
            transactionAdvice.after();
            return result;
        }
    }
    
    //proxy工具类中的getProxy方法
    
    /**
         *
         * @param target 目标类对象
         * @return 返回代理对象
         * @throws Exception
         */
        public static Object getProxyWithProxyMethodAndMyHandler(Object target) throws Exception {
            //通过构造器设置增强类和目标类
            TransactionHandler transactionHandler = new TransactionHandler(new TransactionAdvice(), target);
            Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),transactionHandler);
            return proxy;
        }
    
    
    //测试代码
    @Test
        public void test5() throws Exception /*这里异常我直接抛出了*/ {
            @Test
        public void test5() throws Exception /*这里异常我直接抛出了*/ {
            //目标对象
            IService service = new IServiceImpl();
            //通过newProxyInstance()方法直接获取代理对象
            IService proxy = (IService) ProxyUtil.getProxyWithProxyMethodAndMyHandler(service);
    
            System.out.println(proxy.eat());
            System.out.println(proxy.sleep());
        }
        }
    
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值