我们知道,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使用注解的时候,可以完成注入的功能

Spring的反射机制和依赖注入的更多相关文章

  1. 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  2. Spring的核心机制:依赖注入

    依赖注入的概念 当一个对象要调用另一个对象时,一般是new一个被调用的对象,示例: class  A{ private B b=new B(); public  void  test(){ b.say ...

  3. 深入 Laravel 内核之 PHP 反射机制和依赖注入

    结论: PHP中提供了反射类来解析类的结构: 通过反射类可以获取到类的构造函数及其参数和依赖: 给构造函数的参数递归设置默认值后,即可使用这些带默认值的参数通过 newInstanceArgs 实例化 ...

  4. Spring-----3、Spring的核心机制(依赖注入)

    转载自:http://blog.csdn.net/hekewangzi/article/details/41345237

  5. Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转

    原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...

  6. Spring IOC(三)依赖注入

    本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 1.AbstractBeanFactory ...

  7. Spring的自动装配与依赖注入

    Spring的自动装配与依赖注入 装配 = 创建Bean + 注入Bean 创建Bean 自动发现 显式注册Bean 注入Bean 基于配置的注入 自动注入 Spring的装配分为显式装配和隐式装配, ...

  8. spring学习(二)---依赖注入

    spring第二个特性是依赖注入. 学习依赖注入,首先应该明白两个问题:1,谁依赖谁:2,谁注入,注入什么? 首先还是看代码: 还是这个bean: package testSpring.busines ...

  9. Spring IOC(五)依赖注入

    Spring IOC(五)依赖注入 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 一.autowire 五种注入方式测试 ...

随机推荐

  1. 在eclipse中安装上genymotion插件

    1.安装genymotion-vbox,选择安装目录. 具体安装过程可见http://www.cnblogs.com/wuyudong/p/5601897.html   2.登录并创建模拟器   3. ...

  2. Java中的内部类(成员内部类、静态内部类、局部内部类、匿名内部类)

    Java中的内部类(成员内部类.静态内部类.局部内部类.匿名内部类) 神话丿小王子的博客主页 我们先看这样一段话:人是由大脑.肢体.器官等身体结果组成.而组成我们人体的心脏它也有自己的属性和行为(血液 ...

  3. 干货之运用CALayer创建星级评分组件(五角星)

    本篇记录星级评分组件的创建过程以及CALayer的运用. 为了实现一个星级评分的组件,使用了CALayer,涉及到mask.CGPathRef.UIBezierPath.动画和一个计算多角星关键节点的 ...

  4. 设计模式 之 策略(Strategy)模式

    最近看了<head first 设计模式>一书,便总结了里面的一些内容,今天就简单介绍一下策略模式. 策略模式:定义了算法族,分别封装起来,让他们能够相互替换,此模式让算法的变化独立于使用 ...

  5. js获取url

    location.href 返回完整的url location.origin  返回带协议的主机域名  如http://www.test.com location.pathname  返回url中路径 ...

  6. 玩转CSS3,嗨翻WEB前端,CSS3伪类元素详解/深入浅出[原创][5+3时代]

    在我的上一篇博客中, 很多园友提出说对css3"画图"不是很理解, 在跟他们私聊了一段时间以后,加上自己在开始自学css3的时候的疑惑,我觉得大家之所以不是很理解主要是因为对伪元素 ...

  7. C#显示SQL语句格式

    --SQL SERVER生成测试环境: Create database Test; go USE [Test] GO if OBJECT_ID('Tab','U') is not null drop ...

  8. Java设计模式学习笔记(单例模式)

    最近一直在看<Head First设计模式>,这本书写的确实是很不错的,专注于怎么用最简单的方式最通俗的语言让人了解设计模式.据说GoF的设计模式那本书写的很好,是一本经典,但是就是难懂, ...

  9. ThreadPoolExecutor-线程池开发的使用

    好久没有写过笔记了,最近做的一个项目涉及打线程池和队列的开发,觉得在这个项目中学习到的还是挺多的,对线程安全,并发的知识有加深认知:当然,现在用过的东西并不是代表以后还能娴熟的使用,做好笔记非常重要: ...

  10. Linux下Awk详解(转载)

    什么是Awk Awk是一种小巧的编程语言及命令行工具.(其名称得自于它的创始人Alfred Aho.Peter Weinberger 和 Brian Kernighan姓氏的首个字母).它非常适合服务 ...