springboot的执行过程

@SpringBootApplication注解说明此类是Springboot程序的启动类,是程序的入口
@SpringBootApplication 等价于@Configuration+@EnableAutoConfiguration+@ComponentScan

@Configuration 表明是配置类
@EnableAutoConfiguration:表示程序启动时自动加载springboot默认配置。
@ComponentScan:表示启动时自动扫描当前包及子包下的所有类。

@SpringBootApplication
public class RatelApplication {
    public static void main(String[] args) {
        SpringApplication.run(RatelApplication.class, args);
    }
}

SpringBoot程序启动时,启动类的main方法是程序的入口,执行SpringApplication.run(DemoApplication.class, args);该方法返回一个ConfigurableApplicationContext对象,使用注解的时候返回的具体类型是AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext,当支持web的时候是第二个。

当程序开始启动时,在启动类中调用SpringApplication的静态run方法,此时会执行以下操作:
1、首先新建一个SpringApplication对象;
2、然后执行对象的run()方法;
3、对配置的启动类所在包及子包中的类进行扫描,对于有spring相关注解的类,通过反射为其创建代理对象,并交由spring容器管理

Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成。

@resourse 和@autowired 的区别

@Autowired注解是按照类型(byType)装配依赖对象
@Resource支持name和type两种方式装配依赖对象

@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

Spring 中的bean 是线程安全的吗?

参考:https://wwwblogs/myseries/p/11729800.html
在@Controller/@Service等容器中,默认情况下,scope值是单例-singleton的,线程不安全
在@Controller/@Service等容器中定义静态变量,不论是单例(singleton)还是多实例(prototype)他都是线程不安全的。
默认注入的Bean对象,在不设置scope的时候他也是线程不安全的。

@Scope(value = "prototype") // 加上@Scope注解,他有2个取值:单例-singleton 多实例-prototype

一定要定义变量的话,用ThreadLocal来封装,这个是线程安全的

@RestController
@Scope(value = "singleton") // prototype singleton
public class TestController {

    private int var = 0; // 定义一个普通变量

    private static int staticVar = 0; // 定义一个静态变量

    @Value("${test-int}")
    private int testInt; // 从配置文件中读取变量

    ThreadLocal<Integer> tl = new ThreadLocal<>(); // 用ThreadLocal来封装变量

    @Autowired
    private User user; // 注入一个对象来封装变量

    @GetMapping(value = "/test_var")
    public String test() {
        tl.set(1);
        System.out.println("先取一下user对象中的值:"+user.getAge()+"===再取一下hashCode:"+user.hashCode());
        user.setAge(1);
        System.out.println("普通变量var:" + (++var) + "===静态变量staticVar:" + (++staticVar) + "===配置变量testInt:" + (++testInt)
                + "===ThreadLocal变量tl:" + tl.get()+"===注入变量user:" + user.getAge());
        return "普通变量var:" + var + ",静态变量staticVar:" + staticVar + ",配置读取变量testInt:" + testInt + ",ThreadLocal变量tl:"
                + tl.get() + "注入变量user:" + user.getAge();
    }
}

更多推荐

springboot2-面试题