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.同时操作同一资源(修改,查找不会)
所以存在线程安全问题的情况下不能使用单例.