spring最核心的功能,ioc控制反转。即把对象的管理权交给spring容器,基本的过程是项目启动时扫面报下面的类文件,然后实例化,将实例化的对象以键值对的方式存储在容器中,在项目启动后,程序实现时,可以之间通过对应的键直接到容器中去拿到相应的对象,降低了对象之间的耦合性。
pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tempus.cn</groupId>
<artifactId>spring-ico</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ico Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<finalName>spring-ico</finalName>
</build>
</project>
applicationContext文件
package applicationContext;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class ClassPathApplicationContext implements Serializable{
private static final long serialVersionUID = 1L;
private Map<String,Object> singletonBeanFactory;//存储单例对象容器
private Map<String,Class<?>> beanDefinationFactory;//存储创建类定义对象的容器
private Map<String,Element> beanEleMap;//存储bean的Element对象容器
private Map<String,String> beanScopeMap;//存储bean的scope属性容器
//有参的构造方法,在创建此类实例时需要指定xml文件路径
public ClassPathApplicationContext(String xmlPath) {
singletonBeanFactory = new ConcurrentHashMap<>();
beanDefinationFactory = new ConcurrentHashMap<>();
beanEleMap = new ConcurrentHashMap<>();
beanScopeMap = new ConcurrentHashMap<>();
init(xmlPath);
}
/* 初始化方法,在创建ClassPathApplicationContext时初始化容器
* 并解析xml配置文件,并获取bean元素,在运行时动态创建对象,并为对象属性赋值
* 最后把对象存放在容器中,以供获取
*/
private void init(String xmlPath) {
//使用dom4j解析xml文档,首先创建SAXReader对象
SAXReader reader = new SAXReader();
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(xmlPath);
Document document = reader.read(inputStream);
//获取文档的根元素
Element rootElement = document.getRootElement();
//获取根元素下面所有的bean元素,elements会返回元素的集合
List<Element> elements = rootElement.elements("bean");
for(Element element: elements){
//获得bean的id
String valueId = element.attributeValue("id");
//将element存放到map中,为对象设置属性值时使用
beanEleMap.put(valueId, element);
//获取bean的scope值
String scope = element.attributeValue("scope");
if(scope != null){
beanScopeMap.put(valueId, scope);
}
//获得bean的class路径
String classPath = element.attributeValue("class");
Class<?> cls = Class.forName(classPath);
if(cls != null){
beanDefinationFactory.put(valueId, cls);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*根据bean的id获取容器中的对象,类型为Object*/
public Object getBean(String beanId) {
Class<?> cls = beanDefinationFactory.get(beanId);
Element element = beanEleMap.get(beanId);
String scope = beanScopeMap.get(beanId);
Object obj = null;
try {
// 如果scope为singleton,创建单例对象
if ("singleton".equals(scope) || null == scope) {
// 判断容器中是否有该对象的实例,如果没有,就创建一个实例放到容器中
if (singletonBeanFactory.get(beanId) == null) {
Object instance = cls.newInstance();
singletonBeanFactory.put(beanId, instance);
}
//根据beanId获取对象
obj = singletonBeanFactory.get(beanId);
}
//如果scope为prototype,则创建并返回多例对象
if("prototype".equals(scope)){
obj = cls.newInstance();
}
setFieldValues(beanId,element,scope,cls,obj);
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*此方法为重载,在根据beanId获取容器中对象的同时,还可以转换类型。
*返回指定的类型,在调用该方法时省去强转的步骤,传入第二个参数为指定的类型
*方法实现同上一个方法,只是在返回对向前加了强转
*/
public <T>T getBean(String beanId, Class<T>c){
return (T)getBean(beanId);
}
/*该方法用于对象设置成员属性值*/
private void setFieldValues(String beanId, Element element, String scope, Class<?> cls, Object obj) {
try {
// 获取每个bean元素下面所有的property元素,该元素用于给属性赋值
List<Element> proEles = element.elements("property");
if (null == proEles) {
return;
}
for (Element els : proEles) {
String fieldName = els.attributeValue("name");
String fieldValue = els.attributeValue("value");
//利用反射技术根据name属性值获得类的成员属性
Field field = cls.getDeclaredField(fieldName);
//将该属性设置为可访问(防止成员属性被私有化,导致访问失败)
field.setAccessible(true);
//获取成员属性的类型名称,若非字符串类型,则需要转换
String fieldTypeName = field.getType().getName();
if("int".equals(fieldTypeName) || "java.lang.Integer".equals(fieldTypeName)){
int intFieldValue = Integer.parseInt(fieldValue);
field.set(obj, intFieldValue);
}
if("java.lang.String".equals(fieldTypeName)){
field.set(obj, fieldValue);
}
if("double".equals(fieldTypeName) || "java.lang.Double".equals(fieldTypeName)){
double doubleFieldValue = Double.parseDouble(fieldValue);
field.set(obj, doubleFieldValue);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*销毁方法,用于释放资源*/
public void destroy(){
singletonBeanFactory.clear();
singletonBeanFactory = null;
beanDefinationFactory.clear();
beanDefinationFactory = null;
beanEleMap.clear();
beanEleMap = null;
beanScopeMap.clear();
beanScopeMap = null;
}
}
User类
package entity;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String passWord;
public User() {
System.out.println("无参构造方法执行");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + passWord + "]";
}
}
user.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="user1" class="entity.User" scope="singleton">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="passWord" value="12456"></property>
</bean>
<bean id="user2" class="entity.User" scope="prototype">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
<property name="passWord" value="654321"></property>
</bean>
</beans>
SpringiocTest
package test;
import applicationContext.ClassPathApplicationContext;
import entity.User;
public class SpringIocTest {
public static void main(String[] args) {
//创建ClassPathXmlApplicationContext对象
ClassPathApplicationContext ctx = new ClassPathApplicationContext("User.xml");
//使用手动强转的方式获取单例的User对象
User user1_1 = (User) ctx.getBean("user1");
System.out.println("单例user1_1:"+user1_1);
//使用传入类对象的方式获取单例的User对象
User user1_2 = ctx.getBean("user1",User.class);
System.out.println("单例user1_2:"+user1_2);
//使用手动强转的方式获取多例的User对象
User user2_1 = (User)ctx.getBean("user2");
System.out.println("多例user2_1:"+user2_1);
//使用传入类对象的方式获取多例的User对象
User user2_2 = ctx.getBean("user2",User.class);
System.out.println("多例user2_2:"+user2_2);
}
}
测试结果
无参构造方法执行
单例user1_1:User [id=1, name=张三, password=12456]
单例user1_2:User [id=1, name=张三, password=12456]
无参构造方法执行
多例user2_1:User [id=2, name=李四, password=654321]
无参构造方法执行
多例user2_2:User [id=2, name=李四, password=654321]
这里时通过xml的方式将实例对象注入到容器中,然后通过id从容器中取出来强转成user对象。