浅谈Java反射与SpirngIOC原理

什么的Java中的反射?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

说白了就是在JVM运行时,程序能动态的获取某个类的所有信息。作用就是通过反射机制访问java对象的属性,方法,构造方法等;

Java反射机制使用场景

最经典的就是JDBC加载驱动的Class.forName(... ...);
以及SpringIOC,还有在非常多的框架中多多少少也使用到反射。

SpringIOC

SpringIOC的出现解放了以new的方式获取对象,把每一个bean(实体类)与bean(实体了)之间的关系交给第三方容器进行管理。传统的Spring项目中,使用xml方式作为配置文件声明Bean然后通过容器.getBean("one");获取对象。

思考:SpringIOC底层实现思路是怎么样的?

传统Spring项目使用XML配置文件,里面定义声明了若干Bean,我们先看下XML文件Bean的结构,包含了Class属性,id属性。
在这里插入图片描述
核心思想是通过反射去实例化Bean,最终是用容器.getBean(String bean)的方式获取到对象。反射只需要类路径就能实例化目标对象,属性都已经有了但存储在xml配置文件中,所以我们需要用xml解析技术去读取xml文件。

我们先自定义一个容器对象,容器对象包含一个私有的属性 path,作为该对象的构造入参,这个path代表项目的路径。然后创建一个getBean(String beanId)的方法。

大致代码:

// 容器对象
public class MyXMLContext {
	private String xmlPath;

	public MyXMLContext(String xmlPath) {
		this.xmlPath = xmlPath;
	}

	public Object getBean(String beanId) throws DocumentException, ClassNotFoundException, NoSuchFieldException,
			SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {

		SAXReader saxReader = new SAXReader();
		Document document = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(xmlPath));
		Element rootNode = document.getRootElement();
		List<Element> childElements = rootNode.elements();
		Object bean = null;
		for (Element child : childElements) {
			String xmlbeanId = child.attributeValue("id");
			if (!beanId.equals(xmlbeanId)) {
				continue;
			}
			String beanClassPath = child.attributeValue("class");
			Class<?> forName = Class.forName(beanClassPath);
			bean = forName.newInstance();
			List<Element> e = child.elements();
			for (Element element : e) {
				String name = element.attributeValue("name");
				String value = element.attributeValue("value");
				Field field = forName.getDeclaredField(name);
				field.setAccessible(true);
				field.set(bean, value);
			}
		}
		return bean;
	}

	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException,
			IllegalArgumentException, IllegalAccessException, InstantiationException, DocumentException {
		MyXMLContext appLication = new MyXMLContext("user.xml");
		Object bean = appLication.getBean("darian");
		UserEntity user = (UserEntity) bean;
		System.out.println(user.toString());
	}

}
// 实体类对象,省略了get/set/toString及构造方法
public class UserEntity {
	private String userId;
	private String userName;
}
// xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="darian" class="entity类路径">
		<property name="userId" value="1"></property>
		<property name="userName" value="小明"></property>
	</bean>
	<bean id="coco" class="entity类路径">
		<property name="userId" value="2"></property>
		<property name="userName" value="小红"></property>
	</bean>
</beans>

总结SpringIOC底层实现原理:

  1. 读取XML配置文件
  2. 根据beanId查找bean配置,并获取配置文件中class地址
  3. 使用Java反射技术实例化对象
  4. 获取属性配置,使用反射技术进行赋值

详细细节:

  1. 利用传入的参数获取xml文件的流,并且利用dom4j解析成Document对象
  2. 对于Document对象获取根元素对象<beans>后对下面的标签进行遍历,判断是否有符合的id.
  3. 如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据属性值利用反射建立对象.
  4. 遍历<bean>标签下的property标签,并对属性赋值.注意,需要单独处理int,float类型的属性.因为在xml配置中这些属性都是以字符串的形式来配置的,因此需要额外处理.
  5. 如果属性property标签有ref属性,说明某个属性的值是一个对象,那么根据id(ref属性的值)去获取ref对应的对象,再给属性赋值.
  6. 返回建立的对象,如果没有对应的id,或者<beans>下没有子标签都会返回null

这就是SpringIOC大致的一个实现思路,不过目前大多数已经是使用SpringBoot项目使用注解@Autowired的方式。

关于注解这方面后续会继续…

发布了13 篇原创文章 · 获赞 32 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/QingHe97/article/details/103827464