首先我们回忆一下在我们学习spring或者在我们做项目的时候,肯定都用过基于xml配置bean的方式来配置bean,然后在dao层获取sessionFactory、在service层/biz层获取dao对象、在action层、controller层获取service对象。用的时候都知道在xml里面配置一下bean,给它id和class,在需要注入的bean下面配置上property。那么spring是怎么去帮你创建对象的呢?
看下面代码之前我们先来说说原理:
我们的web项目在启动的时候就会去读取spring的配置文件applicationContext.xml,使用类似于dom4j工具将xml里面的内容读取到java代码里面来,然后根据你传递过来的bean的id和xml里面的bean的id进行匹配,如果发现有,就会把创建的对象传递给你。当然了,我们都知道Spring的bean的作用域常用的有两种,一种是Prototype,一种是Singleton。
Prototype:原型模式,容器初始化的时候并不会创建bean对象,而在getBean的时候创建, 如果多次getBean,则会创建多个bean对象。
Singleton:单例模式,
lazy-init为false(默认是false,所以可以不用设置),则 ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使用该Bean的时候, 直接从这个缓存中取
lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化
下面这个例子就是基于原型模式实现的。
新建一个maven项目
maven依赖的包
<dependencies>
<!-- 引入Spring-AOP等相关Jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
接口的定义:
public interface UserService {
public void add();
public String update();
}
接口的实现类
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("执行了add方法");
}
public String update() {
System.out.println("执行了update方法");
return "abcd";
}
}
自定义的ClassPathXmlApplicationContext.class
import java.io.InputStream;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 手写Spring IoC xml获取bean方式
* @author liuz
*
*/
public class EasyClassPathXmlApplicationContext {
private String xmlPath;
public EasyClassPathXmlApplicationContext(String xmlPath) {
this.xmlPath=xmlPath;
}
public Object getBean(String beanId) throws Exception{
//解析xml 获取所有的bean节点信息
if(beanId.equals("")||StringUtils.isEmpty(beanId)){
throw new Exception("beanId不能为空!");
}
List<Element> readXML=readXML();
if(readXML==null||readXML.isEmpty()){
throw new Exception("xml中未配置bean!");
}
String className=findByElementClass(readXML,beanId);
if(StringUtils.isEmpty(className)){
throw new Exception("该bean对象没有配置class");
}
//3.获取class信息,使用反射初始化
return newInstance(className);
}
/**
* 读取xml里面的节点 使用xml文件中bean的id跟传递过俩的id进行比较
* @param readXML
* @param beanId
* @return class 地址
* @throws Exception
*/
public String findByElementClass(List<Element> readXML,String beanId) throws Exception{
for(Element element:readXML){
//获取属性信息
String xmlBeanId=element.attributeValue("id");
if(StringUtils.isEmpty(xmlBeanId)){
throw new Exception("为获取到bean节点信息");
}
if(xmlBeanId.equals(beanId)){
String xmlClass=element.attributeValue("class");
return xmlClass;
//return newInstance(xmlClass);
}
}
return null;
}
public Object newInstance(String className) throws ClassNotFoundException,
InstantiationException, IllegalAccessException{
Class<?> classInfo=Class.forName(className);
return classInfo.newInstance();
}
/**
* 解析xml
* @throws DocumentException
*/
@SuppressWarnings("unchecked")
public List<Element> readXML() throws DocumentException{
SAXReader saxReader = new SAXReader();
//1.解析xml文件
Document document = saxReader.read(getResourceAsStream(xmlPath));
//读取跟节点
Element rootElement = document.getRootElement();
// 获取下面的子节点
List<Element> elements=rootElement.elements();
return elements;
}
/**
* 获取当前上下文路径
* @param xmlPath
* @return
*/
public InputStream getResourceAsStream(String xmlPath) {
return this.getClass().getClassLoader().getResourceAsStream(xmlPath);
}
}
测试类:
public class Test {
public static void main(String[] args){
EasyClassPathXmlApplicationContext app = new EasyClassPathXmlApplicationContext(
"applicationContext.xml");
UserService userService;
try {
userService = (UserService)app.getBean("userService");
userService.add();
userService.update();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行效果:
源代码下载地址:
链接:https://pan.baidu.com/s/1VsDeLWnHDRtJ4ogITGkMZg 密码:f3i4
具体的实现过程如果看不懂也可以去看余胜军老师的视频。