依赖注入底层反射原理_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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值