zoukankan      html  css  js  c++  java
  • JAVA反射的简单理解

    JAVA 反射有对象反射和方法反射

    主要用户解耦框架的研发,由于没有接触过框架的开发,因此不能理解对象反射和方法反射具体产生了什么样的作用

    个人理解:对象反射和方法反射,不再是以前的new操作,以Person类举例

    以前获取对象: Person person = new Person();

    反射方式获取对象:Person object = (Person)Class.forName('Person').newInstance();

    通常获取调用方法: person.sayHello("张三");

    反射方式调用方法: Method method = object.getClass().getMethod("sayHello", String.class);

                                   method.invoke(object, "张三");

    看上去我们的调用更加不便捷,但是解耦的思想是:代码中取消固定的类的依赖,采用配置等方式解耦,一旦我们需要改动,即改动配置文件或少量配置即可,

    而不用一个类里面大量修改new的对象,这个时候,反射就很好用了,他的类名等都是可以通过外部配置文件加载的,或者在Spring boot中通过注解进行

    装配。

    例举:

    Properties pro=new Properties();
    //获取class目录下的配置文件

    pro.load(ReflectionText.class.getClassLoader().getResourceAsStream("application.properties"));
    //获取配置文件定义的数据
    String className=pro.getProperty("className");
    String methodName=pro.getProperty("methodName");
    //加载该类进内存
    Class cls = Class.forName(className);
    //执行方法
    cls.getMethod(methodName).invoke(cls.newInstance());

    ------------------------------------------------------------------------------------------------------------------------------------------

    动态代理模式的产生
    如果仅仅是通过反射的方式使用类,我们会发现创建起来十分繁琐,且只能直接调用反射好的方法,我理解动态代理模式其实是反射的更加便捷的封装,
    其有两大特点:
    1.同样继承了反射的思想,是反射的更好的封装
    2.可以在调用方法之前和方法之后处理自己的逻辑,例如:基于一个特别的规则,方法就不会被调用了,而这部分逻辑不需要在类里面实现,
    是通过先于类调用做到了拦截,这也产生了后面拦截器的用法。

    动态代理的思想是:创建一个代理对象,该对象和实际对象是映射的,用户在使用的时候,通过代理对象调用实际对象的方法,
    同时,代理对象也可以在自己内部做逻辑处理
    动态代理模式有两种:
    1.JDK模式
    JDK代理模式要求必须提供接口才能使用
    JDK动态代理实现:
    (1).创建一个实际的类(产生实际对象使用)
    创建接口:
    cat HelloWorld.java
    package reflect.jdk;

    public interface HelloWorld {
    public void sayHello();
    }


    实现接口:
    cat HelloWorldImpl.java
    package reflect.jdk;

    public class HelloWorldImpl implements HelloWorld{
    @Override
    public void sayHello() {
    System.out.println("Hello World");
    }
    }
    (2)实现动态代理
    package reflect.jdk;

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

    public class JdkProxyExample implements InvocationHandler {
    //真实对象
    private Object target = null;

    //代理对象
    public Object bind(Object target){
    this.target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    this);
    }
    //代理的方法逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("进入代理方法逻辑");
    System.out.println("在调度真实对象之前的服务");
    Object obj=method.invoke(target, args);
    System.out.println("在调度真实对象之后的服务");
    return obj;
    }
    }
    (3)测试
    package reflect.jdk;

    public class TestJdkProxy {
    public static void main(String args[]){
    JdkProxyExample jdkProxyExample = new JdkProxyExample();

    HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImpl());
    proxy.sayHello();
    proxy.sayHello2();

    HelloWorld a = new HelloWorldImpl();
    a.sayHello();
    }
    }


    2.GCLiB模式
    GCLIB则在没有提供接口的情况下使用,需要提供一个非虚拟类
    1.创建非虚拟类
    cat HelloWorldImpl.java
    
    
    package reflect.jdk;

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


    (2)实现代理
    package reflect.cglib;



    import org.aopalliance.intercept.MethodInvocation;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    public class CglibProxyExample implements MethodInterceptor {
    //生成代理对象
    public Object getProxy(Class cls){
    //CGLIB enhancer 增强类对象
    Enhancer enhancer = new Enhancer();
    //设置增强类型
    enhancer.setSuperclass(cls);
    //定义代理逻辑对象为当前的对象,要求当前对象实现MethodInterceptor的方法
    enhancer.setCallback(this);
    //生成并返回代理对象
    return enhancer.create();
    }

    //代理逻辑方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("调用真实对象前");
    Object result = methodProxy.invokeSuper(o,objects );
    System.out.println("调用真实对象后");
    return result;
    }
    }
    (3)测试
    package reflect.cglib;

    import reflect.jdk.HelloWorld;
    import reflect.jdk.HelloWorldImpl;

    public class TestCglibProxy {
    public static void main(String args[]){
    CglibProxyExample cglibProxyExample = new CglibProxyExample();
    HelloWorldImpl helloWorld = (HelloWorldImpl) cglibProxyExample.getProxy(HelloWorldImpl.class);
    helloWorld.sayHello();
    }
    }


    两种方式的使用都是一样的流程,对象->代理对象->代理逻辑方法
    不同的是,jdk的是一定要先有个对象,为了该对象能够泛化使用,才有了接口
    而cglib是直接传入类,由他自己创建对象,最后仍然是走到逻辑对象和代理逻辑方法上
    而代理方法其实就是之前的method.invoke 的功能

    
    












  • 相关阅读:
    ehcache 的 配置文件: ehcache.xml的认识
    Hibernate的二级缓存(SessionFaction的外置缓存)-----Helloword
    QBC检索和本地SQL检索
    HQL的检索方式
    HQL的第一个程序
    Ubuntu Error: No module named 'apt_pkg' 怎么办?
    Linux 后台运行python .sh等程序,以及查看和关闭后台运行程序操作
    ubuntu install redis/mongo 以及 监控安装
    Mac 上的 redis
    Mac 解决硬盘插入不能写的问题
  • 原文地址:https://www.cnblogs.com/estherSH/p/13971135.html
Copyright © 2011-2022 走看看