学习Spring源码的动机是一次偶然的单元测试, 之前对注入 ,控制反转比较熟悉,先回顾一下当时测试 :
目的:
测试SpringMvc项目中的model层(俗称Service层)
以下的例子均采用注解注入模式,没有在spring.xml中定义bean .
UserModel的代码:
package com.younchen.model; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("personModel") public class PersonModel { @Autowired private Person person; public Person getPerson(){ return person; } public void setPerson(Person person) { this.person = person; } public void showPersonName(){ // System.out.println("姓名:"+person.getName()); } }
userModel( 可以理解为userService ) ,该model中注入了person实体, 所以不能在测试类中以 UserModel userModel = new UserModel() 的方式进行 showPersonName()方法的测试 (推荐mockito 测试框架), 注入需要spring 框架的支持,否则报空指针异常,于是Spring 容器上下文ApplicationContext登场了.
SpringUtil类:
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringUtil { private static ApplicationContext context = null; public static ApplicationContext getApplicationContext() { if (context == null) { context = new ClassPathXmlApplicationContext("spring.xml"); } return context; } public static ApplicationContext getApplicationContext(String path) { return new ClassPathXmlApplicationContext(path); } public static ApplicationContext getAnnotationConfigApplicationContext(String basePackages) { return new AnnotationConfigApplicationContext(basePackages); } }
这个工具类的作用是返回Spring上下文的实例,这样一来可以通过上下文获取spring中配置的bean对象 .
先看一下person类:
package com.younchen.model; import javax.inject.Named; @Named("person") public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Person类中的@Name的作用与spring配置文件中定义<bean name="preson" class="com.younchen.model.person"> 的作用是一样的,前提是spring.xml中定义包扫描器
<context:component-scan base-package="com.younchen.*" />
现在看一下测试类:
package com.younchen.test; import com.younchen.model.PersonModel; import com.younchen.util.SpringUtil; public class ApplicationContext { public static void main(String[] args){ //获取application Context PersonModel personModel = (PersonModel) SpringUtil.getApplicationContext().getBean("personModel"); personModel.getPerson().setName("黑猫"); personModel.showPersonName(); } }
运行结果:
2014-7-8 16:08:46 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@b749757: startup date [Tue Jul 08 16:08:46 CST 2014]; root of context hierarchy 2014-7-8 16:08:46 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring.xml] 2014-7-8 16:08:46 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init> 信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring 姓名:黑猫
依赖注入: 本例中的 Person 类, 无论是 在spring.xml中配置的方式,还是用注解的方式,它都是由spring容器实例化的,不是人为的去new 了一个对象。
控制反转: 本例中不明显, 主程序只是负责调用模块的方法而不去管这个模块的具体实现,经常以工厂模式出现。
依赖注入也是控制反转的一种特殊形态,这里举个例子, 有些时候在userModel中注入的Person 可以是Person的子类(这里可以参考一下 注解方式 同一个实体的不同注解方式 )而userModel的showPersonName方法不管Person的实例具体是哪个类,只负责执行Person的getName方法.
由此对Spring源码产生了兴趣(待续)