Bootstrap

spring基础学习之Ioc-反射简单介绍(四)

Ioc(控制反转:Inverse of Control)是spring容器的内核,AOP,声明事务等功能都是建立在IoC基础上的.
因为IoC这个名字比较晦涩,因此业界又提出了DI(依赖注入:Dependency Injection)的概念用以代替IoC,
即让调用类对某一接口的实现类的依赖关系由容器注入,以移除调用类对这一接口实现的依赖.其中,spring就是这样一个容器,
它通过配置文件或注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入工作.spring为什么这么神奇呢,
这样神奇的力量完全归功于java语言本身的类反射功能,闲话少说,让我简单回顾一下java语言的反射知识吧.
1.java语言反射机制介绍.
java语言允许通过程序化的方式间接对Class的对象实例操作,Class文件由类装载器装载后,在JVM中将形成一份
描述Class结构的元信息对象,通过这些元信息对象可以获取Class的结构信息,如构造函数,属性和方法等.

首先看一个简单的例子,直接看代码.

package com.ilucky.spring.reflect;

/**
 * @author IluckySi
 * @date 20140424
 */
public class User {

	private String username;
	
	private String password;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
	public  void getUserInfo() {
		System.out.println(username + ":" + password);
	}
}
package com.ilucky.spring.reflect;

/**
 * @author IluckySi
 * @date 20140424
 */
public class RegularMainTest {

	public static void main(String[] args) {
		User user = new User();
		user.setUsername("Ilucky");
		user.setPassword("123456");
		user.getUserInfo();
	}
}
/**
输出结果:
Ilucky:123456
*/

如上的主方法是采用传统方式直接调用目标类的方法,下面我们通过java反射机制间接的操作目标类.

直接看代码.

package com.ilucky.spring.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author IluckySi
 * @date 20140424
 */
public class ReflectMainTest {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) throws Throwable {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		Class clazz = classLoader.loadClass("com.ilucky.spring.reflect.User");
		//通过反射机制创建User对象,相当于new User();
		Constructor constructors= clazz.getDeclaredConstructor((Class[])null);//空构造函数.
		User user = (User)constructors.newInstance();
		//通过反射机制设置属性.相当于setUsername("ilucky")和setPassword("123456").
		Method setUsername = clazz.getMethod("setUsername", String.class);//String.class方法中的参数.
		setUsername.invoke(user, "Ilucky");
		Method setPassword = clazz.getMethod("setPassword", String.class);
		setPassword.invoke(user, "123456");
		//输出用户信息.
		Method getUserInfo = clazz.getMethod("getUserInfo");
                getUserInfo.invoke(user);
	}
}
/**
输出结果:
Ilucky:123456
*/
2.类装载器ClassLoader工作机制.
  类装载器是寻找类的字节码文件并构造出类在JVM内部表示的对象组件.在java中,类装载器把一个类装入JVM中,
  主要经过三个步骤:1.装载-查找和导入class文件.2.链接-检查载入的class文件数据的正确定,
  给类的静态变量分配存储空间,将符号的引用转换成直接引用.3.初始化-对类的静态变量,静态代码块执行初始化工作.
  类装载工作由ClassLoader及其子类负责,ClassLoader是一个重要的java运行时系统,他负责在运行时查找和装入class
  的字节码文件.
  JVM在运行时会产生三个ClassLoader:根装载器,ExtClassLoader(扩展类装载器)和AppClasLoader(系统类
  装载器).其中,根装载器不是ClassLoader的子类,它使用C++编写,因此我们在java中看不到他,根装载器负责装载JRE的核心类库,
  如JRE目录下的rt.jar和chartset.jar等.ExtClassLoader和AppClassLoader是ClassLoader的子类,其中ExtClassLoader负责装载

  JRE扩展目录ext中的JAR类包,AppClassLoader负责装载Classpath路径下的类包.直接通过代码看他们之间的关系:

package com.ilucky.spring.classloader;

/**
 * @author IluckySi
 * @date 20140424
 */
public class ClassLoaderTest {

	public static void main(String[] args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		System.out.println("current loader" + classLoader);
		System.out.println("parent loader" + classLoader.getParent());
		System.out.println("parent loader" + classLoader.getParent().getParent());
	}
}
/**
输出结果:
current loadersun.misc.Launcher$AppClassLoader@192d342
parent loadersun.misc.Launcher$ExtClassLoader@6b97fd
parent loadernull
*/
  通过上面的输出结果,可以得知加载class路径下的类包的装载器是AppClassLoader,AppClassLoader的父亲是ExtClassLoader,
  ExtClassLoader的父类是根装载器,因为根装载器是用C++编写的,所以在java中无法获得它的句柄,所以返回结果null.
  JVM装载类时使用"全盘负责委托机制",即先委托父装载器寻找目标类,只有在找不到的情况下,才从自己的类路径下查找并装载目标类.
  ClasLoader是一个抽象类,位于java.lang包中,在这个类里面有很多重要的方法,在这里暂时不做介绍.
3.java反射类.
  Class反射对象描述类语义结构,可以从Class对象中获取构造函数,成员变量和方法等.这些反射类在java.reflect包中,
  其中最主要的三个反射类是Constructor,Method和Field.在这三个反射类中有很多中要的方法,在这里暂时不做介绍.
  此外,java还提供了package反射类,在jdk5.0中还为注解提供了AnnotatedElement发射类.总之,java反射体系保证了可以通过
  程序化的方式访问类中所有的元素,对于private和protected的成员变量和方法,只要JVM的安全机制允许,也可以通过反射进行调用.

  直接通过代码比较.

package com.ilucky.spring.reflect2;

/**
 * @author IluckySi
 * @date 20140424
 */
public class PrivateUser {

	private String username;
	
	private String password;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
	@SuppressWarnings("unused")
	private  void getUserInfo() {
		System.out.println(username + ":" + password);
	}
}
package com.ilucky.spring.reflect2;

/**
 * @author IluckySi
 * @date 20140424
 */
public class RegularMainTest {

	public static void main(String[] args) {
		PrivateUser user = new PrivateUser();
		user.setUsername("Ilucky");
		user.setPassword("123456");
		//如下语句报错: The method getUserInfo() from the type PrivateUser is not visible.
		//user.getUserInfo();
	}
}
package com.ilucky.spring.reflect2;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author IluckySi
 * @date 20140424
 */
public class ReflectMainTest {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) throws Throwable {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		Class clazz = classLoader.loadClass("com.ilucky.spring.reflect2.PrivateUser");
		//通过反射机制创建User对象,相当于new User();
		Constructor constructors= clazz.getDeclaredConstructor((Class[])null);//空构造函数.
		PrivateUser user = (PrivateUser)constructors.newInstance();
		//通过反射机制设置属性.相当于setUsername("ilucky")和setPassword("123456").
		Method setUsername = clazz.getMethod("setUsername", String.class);//String.class方法中的参数.
		setUsername.invoke(user, "Ilucky");
		Method setPassword = clazz.getMethod("setPassword", String.class);
		setPassword.invoke(user, "123456");
		//输出用户信息.
		Method getUserInfo = clazz.getDeclaredMethod("getUserInfo");
		getUserInfo.setAccessible(true);
		getUserInfo.invoke(user, (Object[])null);
	}
}
/**
输出结果:
Ilucky:123456
*/
对于java反射机制的知识先写到这里,这里只是做一下简单的回顾,要想了解更多关于java反射类的知识,上网查吧......

;