问:什么是Spring的IOC?
①IOC(Inversion of Control) 称为控制反转,传统的java开发需要对象我们就直接new或者通过getInstance或者使用反射创建对象。
②在Spring中创建对象可以使用xml配置文件的形式,也可以使用注解@Bean的方式让Spring在启动时创建配置的单例(多例)对象。我们可以直接使用Spring创建好的对象给我们使用。
③bean中的依赖对象也可以DI(Dependency Injection)依赖注入的方式注入需要的bean,DI与IOC是同一个思想。
问:既然说到Spring的创建单例对象那么是单例的?怎么实现?
单例模式就是有且只有一个创建好的对象,提供给需要给其它要用的类。
单例模式有两种实现方式:
①懒汉式:当需要使用的时候才创建对象。
public static Object o = null;
public static synchronized Object getObject(){
if (o == null){
o = new Object();
return o;
}
return o;
}
②饿汉式:已经创建好的
public static Object o = new Object();
public static Object getObject(){
return Object;
}
问:既然有了解到懒汉式与饿汉式的创建单例对象的方式,那么饿汉式应该注意什么问题?
饿汉式的单例对象创建出现线程安全问题,可以使用加锁的方式解决此问题(具体看上问代码)
问:Spring单例模式的Bean式线程安全的吗?
Spring单例模式的bean不是线程安全的,Spring的单例bean都是创建好的放置于bean容器中,所有使用Spring依赖注入的bean都是同一个bean。
Spring的单例bean线程不安全代码演示如下:
@Component
public class MyThread implements Runnable{
@Autowired
Student student;
public void run() {
student.setAge(100);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={MySpringConfig.class})
public class Test1 {
@Autowired
Student student;
@Autowired
MyThread myThread;
@Test
public void testSingle() throws Exception{
student.setAge(300);
Thread thread = new Thread(myThread);
thread.start();
Thread.sleep(3000);
System.out.println(student.getAge());
}
}
结果:
我们先设置的age为300,但是经过thread线程后,age变为100
问:Spring的bean为线程不安全的,那么我们应该在什么情况下应该注意bean的线程安全问题?怎么解决bean线程安全问题?
①看看这个bean有没有全局变量(就是成员变量,成员变量又分为实例变量或者静态变量)
②如果有全局变量,那么你就要注意它是否只能被读取,不会被修改
怎么解决线程安全问题呢?
第一种:可以将bean设置为多例,具体代码如下:
@Bean
@Scope("prototype")
public Student student(){
return new Student("xiaoming", 20);
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={MySpringConfig.class})
public class Test1 {
@Autowired
Student student;
@Autowired
MyThread myThread;
@Test
public void testSingle() throws Exception{
student.setAge(300);
Thread thread = new Thread(myThread);
thread.start();
Thread.sleep(3000);
System.out.println(student.getAge());
}
}
测试结果:
第二种:可以将出项线程安全的对象采用new的方式创建出来,如果对象中使用到了Autoware注入,我们可以在此类上加上注解@Configurable(preConstruction = true)
这个注解的作用是:告诉Spring在构造函数运行之前将依赖注入到对象中。
问:请你答一下Spring的IOC有什么好处?
①依赖注入是一种优秀的解耦方式,依赖注入让Spring的bean通过配置的方式组织在一起,而不是以硬编码的方式耦合在一起
②Spring管理bean的创建和销毁,避免调用者直接使用new直接创建对象,这样会使程序耦合度高,导致程序效率低下。
问:如果直接new创建对象为什么会使程序效率低下呢?
JVM创建对象时,创建的对象会放在堆区域中,对象创建需要JVM在堆区域下开辟对应大小的空间。JVM中存在一个gc回收器,直接new的对象在不使用以后会进行垃圾回收,垃圾回收算法(标记清除、标记整理、复制算法)将不再使用的对象删除,随后整理空间。
问:有看过源码吗?Spring是怎么实现IOC功能的?
(一时半会也想不到比用代码解释更好的办法,索性先用debug跟代码的方式带大家过一遍Spring创建bean的过程,日后如果我想到更好的解释方法,继续更新)
我们要知道一个bean是怎么创建出来的,我们可以使用懒加载的方式(不使用懒加载的方式,bean会在spring启动时全部加载到容器中)使用application获取一个bean
注意我打断点的位置
我们开启debug以后用F7跟进代码,application的getBean方法使用了BeanFactory的来尝试获取name为student的bean类(请注意所有的application都为BeanFactory的实现类)
(日后整理类、方法调用图)