ioc工作原理
读取配置文件 一切配置文件 properties (一般是Application Context.xml
- 配置文件(bean.properties)
UserService=com.ProcessM.Service.impl.UserServiceimpl
UserDao=com.ProcessM.Dao.impl.UserDaoimpl
// 手动模拟ioC 工作原理: 读取properties配置文件(其实这里的properties就是之后的xml其实都一个性质都是配置文件) => 拿到对象 => 实例化容器 => 对象装入容器
public class BeanFactory {
public static Properties properties;
private static HashMap<String, Object> beans;//对象容器 模拟spring ioc容器
static {
//实例化properties对象
properties = new Properties();
try {
//类加载器获取文件流对象
InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
properties.load(is);
//实例化容器
beans = new HashMap<String, Object>();
//取出容器中的keys
Enumeration keys = properties.keys();
//遍历keys
while(keys.hasMoreElements()){
//取出每个key
String key = keys.nextElement().toString();
// 根据key 获取 valuePath 也就是spring 通过id 取对象
String beanPath = properties.getProperty(key);
try {
//反射创建对象
Object value = Class.forName(beanPath).newInstance();
//把key和value放在容器中
beans.put(key,value);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
throw new ExceptionInInitializerError("init bean.properties fail");
}
}
/**
* 根据bean名称获得bean对象 (单例模式getbean)
* @param beanName
* @return beanName
*/
public static Object getBean(String beanName) {
return beans.get(beanName);
}
// 根据bean,名称 get bean对象. (普通模式getbean) 每次创建新对象
public static Object getBean(String beanName) {
String beanPath = properties.getProperty(beanName);
Object bean = null;
try {
bean = Class.forName(beanPath).newInstance();// 每次调用都会创建新bean对象.
}catch (Exception e){
e.printStackTrace();
}
return bean;
}
}
- 测试类
import com.ProcessM.Factory.BeanFactory;
import com.ProcessM.Service.impl.UserServiceimpl;
public class forClassDriverTest {
public static void main(String[] args) {
// UserServiceimpl us = new UserServiceimpl(); 有明显的依赖关系
//此种办法直接给工厂交互 让工厂去管理bean 也就是 ioc 的核心思想
UserServiceimpl us = (UserServiceimpl) BeanFactory.getBean("UserService");
us.addUser();
}
}
Spring 中的 IOC
import com.ProcessM.Dao.UserDao;
import com.ProcessM.Service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class iocTest {
/**
* ApplicationContext 的ioc核心容器 并根据id获取对象
*
* ApplicationContext 的三个常用实现类 :
* ClassPathXmlApplicationContext 加载类路径下的配置文件 , 没有类路径无法加载
* FileSystemXmlApplicationContext 加载磁盘任意位置配置文件 , (必须有访问权限)比如 Macos 的根目录
* AnnotationConfigApplicationContext 读取注解创建容器.
*
* 核心容器的两个接口引发的问题
* ApplicationContext 单例模式适用 实际开发用得更多
* 它在构建核心容器是读取完配置文件就创建对象.
* BeanFactory 多例模式适合 (顶层接口 实现较少)
* 它在构建核心容器时是采用延迟加载的模式,即用户通过id获取对象时创建对象.
* @param args
*/
public static void main(String[] args) {
// --------- 类反射 ApplicationContext ------
//1. 获取核心容器(对象) (交给spring让它去管理bean 工厂模式)
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");//实际开发配置文件最好放在项目中
//ApplicationContext acSystem = new FileSystemXmlApplicationContext("bean.xml");// 配置文件不要放在项目之外
//2. 根据id 获取bean 对象
UserService us = (UserService) ac.getBean("UserService");//一种是自己强转
UserDao uDao = ac.getBean("UserDao", UserDao.class);//一种是字节码强转
UserService us1 = (UserService) ac.getBean("UserService");
// 查看一下
System.out.println("uDao Object: \n" + uDao);
System.out.println("User service Object :\n" + us);
System.out.println(us == us1);
// --------- BeanFactory Mode ---------
Resource resource = new ClassPathResource("bean.xml");
BeanFactory bf = new XmlBeanFactory(resource);// 如果在这里打个断点debug一下, 只有执行getbean方法时对象才被创建.
UserService as = (UserService) bf.getBean("UserService");
}
}
- 执行结果
UserServiceImpl init
uDao Object:
com.ProcessM.Dao.impl.UserDaoimpl@548e7350
User service Object :
com.ProcessM.Service.impl.UserServiceimpl@1a968a59
ture
UserServiceImpl init