有关Spring中IOC的必知必会

问:什么是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的实现类)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(日后整理类、方法调用图)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值