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使用注解的时候,可以完成注入的功能
Spring的反射机制和依赖注入的更多相关文章
- 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入
7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...
- Spring的核心机制:依赖注入
依赖注入的概念 当一个对象要调用另一个对象时,一般是new一个被调用的对象,示例: class A{ private B b=new B(); public void test(){ b.say ...
- 深入 Laravel 内核之 PHP 反射机制和依赖注入
结论: PHP中提供了反射类来解析类的结构: 通过反射类可以获取到类的构造函数及其参数和依赖: 给构造函数的参数递归设置默认值后,即可使用这些带默认值的参数通过 newInstanceArgs 实例化 ...
- Spring-----3、Spring的核心机制(依赖注入)
转载自:http://blog.csdn.net/hekewangzi/article/details/41345237
- Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转
原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...
- Spring IOC(三)依赖注入
本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 1.AbstractBeanFactory ...
- Spring的自动装配与依赖注入
Spring的自动装配与依赖注入 装配 = 创建Bean + 注入Bean 创建Bean 自动发现 显式注册Bean 注入Bean 基于配置的注入 自动注入 Spring的装配分为显式装配和隐式装配, ...
- spring学习(二)---依赖注入
spring第二个特性是依赖注入. 学习依赖注入,首先应该明白两个问题:1,谁依赖谁:2,谁注入,注入什么? 首先还是看代码: 还是这个bean: package testSpring.busines ...
- Spring IOC(五)依赖注入
Spring IOC(五)依赖注入 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 一.autowire 五种注入方式测试 ...
随机推荐
- iOS 设备标识
//UUID NSLog(@"-=-=-=-=-=-=-=-==-=-==qqqqqqqqqqqqqqqqqqqqqqq:::::::::::%@", [[NSUUID UU ...
- 试用Jenkins 2 的 Pipeline 项目
目前Jenkins最新的版本是2.7,现在试用一下pipeline类型的项目,本来想构建一个1.651版本的Jenkins为例,无奈大陆的网络 访问github不稳定,只好改为简单的工程. 目前有一个 ...
- markdown学习笔记 (一)
##类Atx形式标题 # H1标题(一个井号加文字) ### H3标题(三个井号加文字) ###### H6标题(6个井号加文字) 类setext ======== 一级标题(下行加若干个等号) == ...
- luemn PHP_CodeSniffer的安装
1.PHP_CodeSniffer是PEAR中的一个用PHP5写的用来检查嗅探PHP代码是否有违反一组预先设置好的编码标准的一个包,它是确保你的代码简洁一致的必不可少的开发工具,甚至还可以帮助程序员减 ...
- .net开发过程中遇到的错误,及解决办法记录
一.在证书存储区中找不到清单签名证书. 解决方法:右击项目属性—>签名—>为ClickOnce清单签名,将勾掉的选项去掉. 参考:http://www.cnblogs.com/190196 ...
- OOP应用:实体类
实体类 定义:实体类是一个业务实体的类,而业务实体就是整个软件系统业务所涉及的对象. 使用: 1.新增实体类项目,增加类库项目,以.Modes作为后缀. 2.抽取对象以及属性.(简单地说,对象就是每个 ...
- MySQL数据库的导入和导出
1.导入数据库 在命令行下输入: mysql -u username -p test < /home/data/test.sql 说明: username 是 ...
- RTP、RTCP协议学习-2015.04.15
最近做视频编解码部分,传输采用RTP协议.对学习做个记录 1.简介 实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工 ...
- linux下memcached的安装
系统镜像及环境要求: 1) 适用于windows系列版本及开发者的相关教程 请参考本文1.0开始安装步骤 2) Centos 6系列及Aliyun Linux 6系列以上版本 请参考本文2.0开始 ...
- python脚本实现自动保留ctime最近的几个文件
使用了给字典排序的sorted方法 #!/usr/bin/env python # coding:utf-8 import os def rm_backup(rm_path,days): files_ ...