zoukankan      html  css  js  c++  java
  • spring的反射机制和注入

     


    我们知道,Spring中大量使用了反射机制,那么究竟是什么地方使用了呢?

    spring的一大核心概念是注入,

    但是,这存在的一个前提就是类是由spring管理起来的。

    反射是根据className生成一个具体的实例

    这是一个很实用的思想。

    比如:当我们需要根据传进来的参数的类型,选择具体的实现类时,

    反射机制就能很好的解决问题。

    然而,一般我们使用反射机制,创建的代理类是根据构造函数实例化的。

    而不是从spring容器中注入 。

    这样就会导致一个问题,无法在创建的代理类中实现注入功能。

    当然,如果你一定要使用的话,系统会提示空指针错误。

    这个时候,如果把反射创建的类由spring注入就可以有效的解决这个问题 。

    这样也存在一个问题。

    就是获得spring的ApplicationContext.

    如果我们重新获得一遍的话,

    这样就是对系统资源极大的浪费。

    这样我们可以声明一个静态变量将ApplicationContext保存起来

        // 声明一个静态变量保存
        public void setApplicationContext(ApplicationContext contex)
                throws BeansException {
            MyApplicationContextUtil.context = contex;
        }

    并将其用spring容器管理起来。

    这样的话,我们就可以很轻松的获得ApplicationContext,而不需要消耗太多的系统资源。

    从而,很简单的,

    当我们的实现类全部继承一个相同的接口时,

    我们的接口便可以通过反射初始化。

    从而,创建不同的具体实现类。

    同时,因为所有的类都是通过spring管理起来的。

    很明显,在创建的实现类中也是可以使用spring的注入。

    而不是有空指针错误。

    一  反射源头Class类

    对类的概念我们已经非常熟悉了。比如可以有Student这个类,Person这个类。但是我们要知道,有一个叫Class的类,它是反射的源头。

    正常方式:通过完整的类名—>通过new实例化—>取得实例化对象

    反射方式:实例化对象—>getClass()方法—>通过完整的类名

    一个简单的例子:

    package cn.classes;

    public class OneClass {

    }


    package cn.test;

    import cn.classes.OneClass;

    public class Test {
        public static void main(String[] args) {
            OneClass c = new OneClass();
            System.out.println(c.getClass().getName());
       }
    }

    输出结果:cn.classes.OneClass


    我们需要使用反射,就要获得Class这个类,有三种方法:

    package cn.classes;

    public class OneClass {

    }


    import cn.classes.OneClass;

    public class Test {
    public static void main(String[] args) {
         Class<?> c1 = null;
         Class<?> c2 = null;
         Class<?> c3 = null;

         try 
        {
             // 方法一:forName(重要)
             c1 = Class.forName("cn.classes.OneClass");
        } 
        catch (ClassNotFoundException e) 
        {
             e.printStackTrace();
        }
         // 方法二
         c2 = new OneClass().getClass();
      
         // 方法三
         c3 = OneClass.class;

         System.out.println(c1.getName());
         System.out.println(c2.getName());
         System.out.println(c3.getName());
       }
    }

    输出结果:cn.classes.OneClass

    二 利用Class这个类实例化类

    ①无参构造

    package cn.classes;

    public class Person {
        private String name;
        private int age;

         .............省略getter,setter..............

        @Override
        public String toString()
        {
              return "Person [name=" + name + ", age=" + age + "]";
        }

    }


    package cn.test;

    import cn.classes.Person;

    public class Test
    {
        // 这样做必须在类中有一个空构造方法
        public static void main(String[] args)
        {
                  Class<?> c = null;
                   try
                   {
                          c = Class.forName("cn.classes.Person");
                          Person p = (Person)c.newInstance();
                          p.setName("xy");
                          p.setAge(20);
                          System.out.println(p);
                   } 
                  catch (Exception e)
                  {
                          e.printStackTrace();
                   }  
         }
    }

    ②有参构造

    package cn.classes;

    public class Person
    {
        private String name;
        private int age;

        .............省略getter,setter..............    

        @Override
        public String toString()
        {
              return "Person [name=" + name + ", age=" + age + "]";
        }
    }


    package cn.test;

    import java.lang.reflect.Constructor;

    import cn.classes.Person;

    public class Test
    {
        // 如果没有一个空构造方法
        public static void main(String[] args)
        {
              Class<?> c = null;
              try
              {
                      c = Class.forName("cn.classes.Person");
                      Constructor<?>[] cons = c.getConstructors();
                      Person p = (Person)cons[0].newInstance("xy",20);
                      System.out.println(p);
              } 
             catch (Exception e)
             {
                    e.printStackTrace();
             }  
        }
    }

    三 Spring中使用Class实例化

    bean.xml
    <bean id="id" class="com.xy.Student" />

    Spring将采用的代码创建代码Java实例
    Class c = Class.forName("com.xy.Student");
    Object bean = c.newInstance();

    四 Class类调用方法

    package cn.classes;

    public class Person
    {
        public void add()
        {
               System.out.println("add");
        }

        public void addWithParameters(String name, int age)
        {
                System.out.println("add带参数方法" + name + age);
        }
    }


    package cn.test;

    import java.lang.reflect.Method;

    public class Test
    {
        public static void main(String[] args)
        {
                 Class<?> c1 = null;
                 try
                 {

                       c1 = Class.forName("cn.classes.Person");

                       // 不带参数的方法调用
                       Method m = c1.getMethod("add");
                       m.invoke(c1.newInstance());

                       // 带参数方法调用
                       Method m1 = c1.getMethod("addWithParameters", String.class, int.class);
                       m1.invoke(c1.newInstance(), "xy", 22);
                }
                catch (Exception e)
                {
                       e.printStackTrace();
                }
        }
    }

    五 Class获得getter,setter方法

    Class这个类可以获得类的很多信息,比如获得该类的接口,构造函数,属性,方法等。我们来看如何获得getter,setter方法。

    package cn.classes;

    public class Person
    {
        private String name;
        private int age;

        省略getter,setter  

     }

    package cn.test;

    import java.lang.reflect.Method;

    public class Test
    {
        public static void main(String[] args)
        {
               Class<?> c1 = null;
               Object obj = null;
               try
               {
                         c1 = Class.forName("cn.classes.Person");
                         obj = c1.newInstance();
                         setter(obj, "name", "xy", String.class);
                         setter(obj, "age", 20, int.class);
                         getter(obj, "name");
                         getter(obj, "age");
               }
               catch (Exception e)
                {
                        e.printStackTrace();
                }
       }

       /**
        * @param obj:要操作的对象
        * @param att:要操作的属性
        * @param value:要设置的属性内容
        * @param type:要设置的属性类型
        */
        public static void setter(Object obj, String att, Object value, Class<?> type)
        {
             try
             {
                // 得到setter方法
              Method m = obj.getClass().getMethod("set" + initStr(att), type);
              m.invoke(obj, value);
             }
             catch (Exception e)
             {
              e.printStackTrace();
             }
       }

       /**
        * @param obj:要操作的对象
        * @param att:要操作的属性
        */
       public static void getter(Object obj, String att)
       {
            try
            {
                   // 得到getter方法
                   Method m = obj.getClass().getMethod("get" + initStr(att));
                   System.out.println(m.invoke(obj));
            }
           catch (Exception e)
           {
                   e.printStackTrace();
           }
       }

       public static String initStr(String oldStr)
       {
             String newStr = oldStr.substring(0, 1).toUpperCase() + oldStr.substring(1);
             return newStr;
       }
    }

    六 Spring调用getter,setter方法

    我们以setter注入例子

    bean.xml
    <bean id="id" class="com.xy.Student">
        <property name="stuName" value="xy" />
    </bean>


    Spring将采用的代码创建代码Java实例,并注入值:
    Class c = Class.forName("com.xy.Student");
    Object bean = c.newInstance();


    通过一些操作获取对stuName对应的setter方法名
    String setname = "set" + "StuName";
    Method method = c.getMehod(setname,String.Class);
    method.invoke(bean,"xy");

    这样就完成了最基本的注入操作。当然,Spring还可以通过构造函数进行注入。这样就参考第二点有参构造的Class的使用。

    Class还可以访问Annotation,这样就Spring使用注解的时候,可以完成注入的功能。

     

  • 相关阅读:
    数据分析的数据来源都有哪些?
    数据分析的技能要求及分析流程
    (原创)使用matlab-cftools拟合工具的问题
    Spring加载xml配置文件的方式
    Spring-ResolvableType可解决的数据类型
    从list中取N个随机生成一个集合
    AOP统一处理修改人、创建人、修改时间、创建时间
    Java依据集合元素的属性,集合相减
    java去掉数字后面的0
    数字格式化NumberFormat
  • 原文地址:https://www.cnblogs.com/a892647300/p/2653993.html
Copyright © 2011-2022 走看看