来谈谈 Java 反射机制,动态代理是基于什么原理?

目录

1 一些概念

2 动态代理解决了什么问题,在你的业务系统中的应用场景是什么?

1 一些概念

首先我们来看一些概念性的描述:

注解(Annotation):也叫元数据。一种代码级别的说明。它是JDK 1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

反射:赋予程序在运行时自省(introspect)的能力。指的是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。

静态代理:事先写好代理类,缺点是每个业务类都要对应一个代理类,非常不灵活。

动态代理:运行时自动生成代理对象,是一种方便运行时动态处理代理方法调用的机制。很多场景都是利用类似机制,比如:用来包装RPC调用、面向切面编程(AOP)。通过代理可以让调用者和实现者之间解耦。

JDK动态代理:代理类需要实现JDK的  InvocationHandler 接口 ,其中 完成真实方法的调用是通过 invoke 方法来实现的。必须实现了接口的类才能用这种办法生成代理对象,依赖接口。

cglib动态代理:通过生成类的子类作为代理类,对于接口的依赖被克服了。

AOP:面向切面编程。在不影响原有功能的情况下,对程序进行横向扩展。说说我自己的理解吧。某个类的方法已经封装好了,现在我们要对原有的方法进行干预,但是又不能破坏原来的类,这时候就需要aop的思想,把这个切点扩展成一个面来进行操作。(也就是生成该类的代理,对代理进行操作

依赖注入(控制反转):Spring是通过反射来实现依赖注入的。什么是依赖呢? 如果在A类里面调用B类,那么A类需要依赖于B类,通常的话,是A类来创建B类的示例。但是spring 里面,创建的动作由spring容器来完成,然在在运行的时候注入到A类中,所以叫做依赖注入。比如说注解@Resource和@Autowired等

  • 正常方式:通过完整的类名—>通过new实例化—>取得实例化对象
  • 反射方式:实例化对象—>getClass()方法—>通过完整的类名

总结: 反射和动态代理都是运行时的机制。通过反射,我们可以在运行时操作类或者对象。而动态代理,它是一个代理机制,代理可以看做是对调用目标的一个包装,代理除了可以调用目标,还可以做一些其他的操作。通过代理可以让调用者与实现者解耦。动态代理是运行的时候才自动生成代理对象,如果是编码阶段显式的指定代理类,就是静态代理了。

 

2 动态代理解决了什么问题,在你的业务系统中的应用场景是什么?

通过代理可以让调用者和实现者之间解耦。

JDK的动态代理:通常代理类需要实现JDK的  InvocationHandler 接口 ,其中 完成真实方法的调用是通过 invoke 方法来实现的。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。

public class DynamicProxy {

    public static void main(String[] args) {
        HelloImpl hello = new HelloImpl();

        //实现对应的InvocationHandler
        MyInvocationHandler handler = new MyInvocationHandler(hello);
        // 构造代码实例
        Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
        // 调用代理方法
        proxyHello.sayHello();
    }
}


    interface Hello {
        void sayHello();
    }


    class HelloImpl implements  Hello {
        @Override
        public void sayHello() {
            System.out.println("Hello World");
        }
    }

    class MyInvocationHandler implements InvocationHandler {
        private Object target;
        public MyInvocationHandler(Object target) {
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("Invoking sayHello");
            Object result = method.invoke(target, args);
            return result;
        }
    }

JDK proxy 的动态代理,其实现过程可以简化为:

  • 提供一个基础的接口,作为被调用类型和代理类型之间的统一入口,如上面代码的interface Hello
  • 实现 invocationHandle接口,即被调用的方法都由 invocationHandle 来处理,其方法 invoke ()是真正的动作逻辑。
  • 通过Proxy 类,调用  newProxyInstance ,在运行时动态生成代理类的实例。(动态代码生成就在这个阶段)

 

JDK proxy 的方法,有接口的依赖,那如果被调用者没有实现接口,而我们还希望利用动态代理机制,怎么办? 

我们知道,Spring AOP 支持两种方式的动态代理,JDK proxy 和 cglib,如果我们选择cglib方式,cglib 是通过 asm 直接操作字节码,所以可以不实现接口。cglib 动态代理采用的是创建目标类的子类的方式,因为是子类,可以达到近似使用被调用者本身的效果。

通过代理静默的解决一些业务无关的问题,比如:安全、事务、日志、资源关闭,让开发者可以只关心于他的业务。

 

以上,有点晦涩。有时间再补充扩展吧。?

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值