Spring IOC中java反射技术的深入了解
再说Spring IOC(控制反转)之前我们先简单说一下java的反射技术,对他了解了那么对于理解spring的底层实现就容易多了
Spring 的底层是 Dom4j+java 反射机制 ,Dom4j解析XML,反射机制主要是实例化bean.
一:先说一下反射技术创建类的三种方式
//第一种方法:forName Class<?> class1 = Class.forName("com.app.Person"); Objectclass1 =cls.newInstance();
//第二张方法:class Class<?> class2 = Person.class;
//第三种方法:getClass Person person = new Person(); Class<?> class3 = person.getClass();
面试时我们经常会问到这样一个问题:
问:new和newInstance关键字之间的区别
答:(1)在执行Class.forName("a.class.Name")时,JVM会在classapth中去找对应的类并加载,这时JVM会执行该类的静态代码段。在使用newInstance()方法的时候,必须保证这个类已经加载并且已经连接了,而这可以通过Class的静态方法forName()来完成的。
使用关键字new创建一个类的时候,这个类可以没有被加载,一般也不需要该类在classpath中设定,但可能需要通过classlaoder来加载。
(2)new关键字能调用任何构造方法。
newInstance()只能调用无参构造方法。
如果你能答出来,那么恭喜你,由这个问题又衍生出两个问题
1.既然使用newInstance()构造对象的地方通过new关键字也可以创建对象,为什么又会使用newInstance()来创建对象呢?
答:主要提高可伸缩性、可扩展性,看下面这句代码,如果需要修改的话,那个更容易些呢?
Door door = (Door) Class.forName(className).newInstance();
Door door = new AutoDoor() ;
2.ClassLoader.loadClass和Class.forName的区别?
答:Class.forName得到的class是已经初始化完成的,也就是说已经执行类变量赋值和静态代码块.
Classloder.loaderClass得到的class是还没有链接的,也就是没有执行类变量和静态代码块.
别说我问题多,解决一个问题,可以帮助我们检查相关的知识,达到知其然和其所以然,只有这样时间长了,我们才能达到触类旁通.
二:控制反转和依赖注入是从不同方面讲的同一个东西
OC:即“控制反转”,不是什么技术,而是一种思想。使用IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
DI:依赖注入,解决对象之间的依赖关系。
本篇文章主要讲解一下IOC底层实现的原理(反射),Bean容器的实现,就不对IOC的概念进行详述了。
在Spring的配置文件中,经常看到如下配置:
[html] view plain copy
- <bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl"></bean>
那么通过这样配置,Spring是怎么帮我们实例化对象,并且放到容器中去了了?对,就是通过反射!!!
下面是Spring通过配置进行实例化对象,并放到容器中的伪代码:
[html] view plain copy
- //解析<bean .../>元素的id属性得到该字符串值为“courseDao”
- String idStr = "courseDao";
- //解析<bean .../>元素的class属性得到该字符串值为“com.qcjy.learning.Dao.impl.CourseDaoImpl”
- String classStr = "com.qcjy.learning.Dao.impl.CourseDaoImpl";
- //利用反射知识,通过classStr获取Class类对象
- Class<?> cls = Class.forName(classStr);
- //实例化对象
- Object obj = cls.newInstance();
- //container表示Spring容器
- container.put(idStr, obj);
通过解析xml文件,获取到id属性和class属性里面的内容,利用反射原理获取到配置里面类的实例对象,存入到Spring的bean容器中。
当一个类里面需要应用另一类的对象时,Spring的配置如下所示:
[html] view plain copy
- <bean id="courseService" class="com.qcjy.learning.service.impl.CourseServiceImpl">
- <!-- 控制调用setCourseDao()方法,将容器中的courseDao bean作为传入参数 -->
- <property name="courseDao" ref="courseDao"></property>
- </bean>
我们继续用伪代码的形式来模拟实现一下Spring底层处理原理:
[java] view plain copy
- //解析<property .../>元素的name属性得到该字符串值为“courseDao”
- String nameStr = "courseDao";
- //解析<property .../>元素的ref属性得到该字符串值为“courseDao”
- String refStr = "courseDao";
- //生成将要调用setter方法名
- String setterName = "set" + nameStr.substring(0, 1).toUpperCase()
- + nameStr.substring(1);
- //获取spring容器中名为refStr的Bean,该Bean将会作为传入参数
- Object paramBean = container.get(refStr);
- //获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象
- Method setter = cls.getMethod(setterName, paramBean.getClass());
- //调用invoke()方法,此处的obj是刚才反射代码得到的Object对象
- setter.invoke(obj, paramBean);
通过上面对Spring底层原理的分析,可以发现,其实并不难,用到的都是反射机制,通过反射实例化对象,存入到Spring的bean容器中。
第二部分内容属于转载: http://blog.****.net/mlc1218559742/article/details/52774805
最后一个问题:
问:spring ioc的优缺点?
答:优点:反射一般在框架中使用较多。因为框架要适用更多的情况。对灵活性要求较高。
缺点:运用反射会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。
只要在代码或配置文件中看到类的完整路径(包.类),其底层原理基本上使用的就是Java的反射机制。
稍微拓展一下,Spring的Aop的底层原理是用到设计模式,动态代理模式.
动态代理又分为jdk动态代理和cglib代理,源码里面会有一个判断,如果被代理对象实现了接口,那么默认使用JDK动态代理,如果代理对象没有实现任何接口,那么就默认使用CGlib动态代理。
IOC的基本流程!