spring Ioc大致原理
就是实现解耦
最初我们对象都是用来调用,比如
Student stu = new Students()
到多态接口以后,我们是这样:
Person p = new Student();//多态,Student类继承了Person类
List list = new ArrayList();//多态 接口类型 Arraylist实现了List接口
反射阶段:
String classPath = "类的全路径"
Object obj = Class.forName(classPath).getInstance()
反射+配置文件
//读取配置文件beans.properties(src目录下)
ResourceBundle rb = ResourceBundle.getBundle("beans");
//获取配置文件中的userService的实现类的全限定名
String userServiceClassPath = rb.getString("userService");
UserService userService = null;
try {
//反射机制创建对象
userService = (UserService)Class.forName(userServiceClassPath).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
userService.register();
spring Ioc(反射+配置文件+工厂模式)
beans.properties配置文件
UserService=com.ithaima.service.impl.UserServiceImpl
BeansFactory工厂类
/**
* 工厂模式:
* 专门用来创建对象的。
* 将对象有原先 new 的方式,替换成反射+配置的方式。
* 好处:
* 1.解耦
* 2.可以管理我们的bean
*/
public class BeansFactory {
//多例工厂:每调用一次方法创建一次对象
public static Object getBean(String beanName) {
Object obj = null;
ResourceBundle rb = ResourceBundle.getBundle("beans");
String classPath = rb.getString(beanName);
try {
obj = Class.forName(classPath).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
/**
* 单例工厂:
* 思路:
* 第一次创建,第二次都是应该获取第一次创建的对象。
* 工厂能够创建多个对象,所以声明集合类型来保存。我们还需要从工厂中获取制定的对象。
* 选择map集合。
*
* 步骤:
* 1.声明一个map集合类型变量,保存创建的对象。
* 2.优先从map中获取对象,如果没有就创建,并且保存。
*/
private static HashMap<String, Object> beanMap = new HashMap<>();
public static Object getBean2(String beanName) {
Object obj = beanMap.get(beanName);
if (obj == null) {
//创建对象
String classPath = ResourceBundle.getBundle("beans").getString(beanName);
try {
obj = Class.forName(classPath).newInstance();
//将创建的obj放入hashmap中
beanMap.put(beanName, obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return obj;
}
public static void main(String[] args) {
//多例
Object userService = BeansFactory.getBean("UserService");
System.out.println("userService = " + userService);//userService = com.ithaima.service.impl.UserServiceImpl@511d50c0
Object userService1 = BeansFactory.getBean("UserService");
System.out.println("userService1 = " + userService1);//userService1 = com.ithaima.service.impl.UserServiceImpl@60e53b93
//单例
Object userService2 = BeansFactory.getBean2("UserService");
System.out.println("userService2 = " + userService2);//userService2 = com.ithaima.service.impl.UserServiceImpl@5e2de80c
Object userService3 = BeansFactory.getBean2("UserService");
System.out.println("userService3 = " + userService3);//userService3 = com.ithaima.service.impl.UserServiceImpl@5e2de80c
}
}
比较:
单例模式与多例模式的区别:
实现类
public class UserServiceImpl implements UserService {
public UserServiceImpl() {
System.out.println("无参执行,对象创建");
}
public void init() {
System.out.println("方法初始化");
}
@Override
public void login() {
System.out.println("登录了");
}
public void destroy() {
System.out.println("方法销毁");
}
}
applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean definitions here -->
<bean id="UserService" class="com.itheima.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy" scope="singleton"></bean>
</beans>
测试类
@Test
public void login() {
//1.解析核心配置
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.调用工厂对象的方法来创建对象
System.out.println("开始获取对象");
UserService userService = (UserService)ac.getBean("UserService");
System.out.println("userService = " + userService);
UserService userService2 = (UserService)ac.getBean("UserService");
System.out.println("userService2 = " + userService2);
}
单例模式的结果:singleton
十二月 13, 2019 2:34:02 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7a92922: startup date [Fri Dec 13 14:34:02 CST 2019]; root of context hierarchy
十二月 13, 2019 2:34:02 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
无参执行,对象创建
方法初始化
开始获取对象
userService = com.itheima.service.impl.UserServiceImpl@27808f31
userService2 = com.itheima.service.impl.UserServiceImpl@27808f31
十二月 13, 2019 2:34:02 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7a92922: startup date [Fri Dec 13 14:34:02 CST 2019]; root of context hierarchy
方法销毁
Process finished with exit code 0
当配置文件一加载,对象就被创建,然后调用初始化方法,容器一销毁,destroy被调用,对象就被销毁.两次创建的对象是同一个对象.
现在我将配置文件改为多例模式:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean definitions here -->
<bean id="UserService" class="com.itheima.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy" scope="prototype"></bean>
</beans>
测试类
@Test
public void login3() {
//1.解析核心配置
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.调用工厂对象的方法来创建对象
System.out.println("开始获取对象");
UserService userService = (UserService)ac.getBean("UserService");
System.out.println("userService = " + userService);
UserService userService2 = (UserService)ac.getBean("UserService");
System.out.println("userService2 = " + userService2);
ac.close();
}
结果:
十二月 13, 2019 2:40:06 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7a92922: startup date [Fri Dec 13 14:40:06 CST 2019]; root of context hierarchy
十二月 13, 2019 2:40:06 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
开始获取对象
无参执行,对象创建
方法初始化
userService = com.itheima.service.impl.UserServiceImpl@1a8a8f7c
无参执行,对象创建
方法初始化
userService2 = com.itheima.service.impl.UserServiceImpl@2353b3e6
十二月 13, 2019 2:40:06 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7a92922: startup date [Fri Dec 13 14:40:06 CST 2019]; root of context hierarchy
Process finished with exit code 0
多例模式下:配置文件加载后并没有立马进行创建对象,而是在调用方法时才创建对象,并且容器销毁后并没有调用destroy方法销毁对象.对象由垃圾回收机制进行垃圾回收.观察到地址不一致,两次创建的对象不是同一个对象.
如果是scope属性值为singleton
一个应用只有一个对象的实例。它的作用范围就是整个应用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
如果scope属性值为prototype
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例(getBean)。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被java的垃圾回收器回收了。
因为单例的实现原理是底层会new一个map集合,把创建后的对象放在map集合中,当容器关闭时,可以对map集合中的对象进行
操作.而多例在创建对象时并没有创建集合去保存对象,对象被创建后直接返回给调用者.只有当对象不用时,才会被垃圾回收
机制进行回收销毁.
使用:
controller使用多例,service和dao使用单例.因为单例能够节省资源,所以优先使用单例,但是,单例模式不能使用在存在线程安全的情况下.
存在线程安全问题的前提条件是:
1.多线程并发 2.同时操作同一资源(修改,查找不会)
所以存在线程安全问题的情况下不能使用单例.