为了避免传统的在表现层、业务层、dao层之间的new 这样的耦合,现在我们手写工厂类,谁需要谁去工厂里getBean(name),
package com.itheima.com.itheima;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class BeanFactory {
/ **
* 创建一个Bean对象工厂,用于管理创建对象
* 它就是我们创建service和dao对象的
* 目的:
* 1、 需要一个配置文件来配置我们的service和dao配置的内容,唯一表示=全限定类名
* 2、 通过读取配置文件配置内容,利用反射创建对象
*/
private static Properties props;
//使用静态代码块为Properties对象赋值
static {
try {
//1 获取对象
props=new Properties();
//2 获取properties文件流对象
InputStream in =BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
} catch (IOException e) {
throw new ExceptionInInitializerError("初始化失败");
}
}
//根据Bean的名称获取bean对象
public static Object getBean(String beanName) {
Object bean=null;
try {
String beanPath =props.getProperty(beanName);
System.out.println(beanPath);
bean=Class.forName(beanPath).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return bean;
}
}
/*----------------------------------
原始的用反射机制创建对象,但调用一次getBean则创建一次对象
所以下面改进,将反射机制穿件的对象放进一个容器里,同时将全限定类名作为key,
对象实例作为value,以后再getBean时则直接拿出来即可
*/
//改进后的BeanFactory
public class BeanFactory {
/**
* 创建一个Bean对象工厂,用于管理创建对象
* 它就是我们创建service和dao对象的
* 目的:
* 1、 需要一个配置文件来配置我们的service和dao配置的内容,唯一表示=全限定类名
* 2、 通过读取配置文件配置内容,利用反射创建对象
*/
private static Properties props;
//定义一个Map,用于存放我们要创建的对象,可以称之为容器
private static Map<String ,Object> beans;
//使用静态代码块为Properties对象赋值(静态代码块只执行一次 ,执行完成时,beans也就已经是包含了很多 对象的容器了)
static {
try {
//1 获取对象
props=new Properties();
//2 获取properties文件流对象
InputStream in =BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
beans=new HashMap<String,Object>();
Enumeration keys=props.keys();
while (keys.hasMoreElements()){
String key=keys.nextElement().toString();
//根据key获取value
String beanPath =props.getProperty(key);
//反射创建对象
Object value=Class.forName(beanPath).getNestHost();
//将创建的对象放入到容器中
beans.put(key,value);
}
} catch (IOException | ClassNotFoundException e) {
throw new ExceptionInInitializerError("初始化失败");
}
}
//根据Bean的名称获取bean对象 这次直接从对象中获取对象
public static Object getBean(String beanName) {
return beans.get(beanName);
}
}
这样,我们初步手写了spring的 容器原理。
下面才是真的使用spring
package com.itheima.ui;
import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
/**
* 获取spring的Ioc核心容器,并根据id获取对象
*
* ApplicationContext的三个常用实现类:
* ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
* FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
*
* AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。
*
* 核心容器的两个接口引发出的问题:
* ApplicationContext: 单例对象适用 采用此接口
* 它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
*
* BeanFactory: 多例对象使用
* 它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
* @param args
*/
public static void main(String[] args) {
//1.获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml");
//2.根据id获取Bean对象
IAccountService as = (IAccountService)ac.getBean("accountService");
IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);
System.out.println(as);
System.out.println(adao);
as.saveAccount();
//--------BeanFactory----------
// Resource resource = new ClassPathResource("bean.xml");
// BeanFactory factory = new XmlBeanFactory(resource);
// IAccountService as = (IAccountService)factory.getBean("accountService");
// System.out.println(as);
}
}