Spring中Bean的作用域与生命周期

文章目录


Bean的作用域

在IOC中可以通过 @Controller,@Service,@Repository,@Component,@Configuration,@Bean 来声明Bean对象,通过 ApplicationContext 或者 BeanFactory 来获取对象;或通过 @Autowired , Setter 方法或者构造方法等来为应用程序注入所依赖的Bean对象。

对于下面的代码,两个Bean对象输出的结果一致

java 复制代码
@SpringBootTest
class DemoApplicationTests {
    @Autowired
    private ApplicationContext applicationContext; //Spring 容器

    @Test
    void contextLoads() {
        Dog dog1 = applicationContext.getBean(Dog.class);
        dog1.setName("狗狗1");
        System.out.println(dog1);//狗狗1
        System.out.println(dog1.getName());//com.example.demo.scope.Dog@2b10ace9
        Dog dog2 = applicationContext.getBean(Dog.class);
        System.out.println(dog2);//狗狗1
        System.out.println(dog2.getName());//com.example.demo.scope.Dog@2b10ace9
    }
}

在Spring中支持以下几种种作用域,后4种在Spring MVC环境才生效:

  • singleton:单例作用域,每个Spring IoC容器内同名称的bean只有一个实例(单例)(默认)
  • prototype:原型作用域(多例作用域),每次使用该bean时会创建新的实例(非单例)
  • request:请求作用域,每个HTTP请求生命周期内,创建新的实例(web环境中,了解)
  • session:会话作用域,每个HTTP Session生命周期内,创建新的实例(web环境中,了解)
  • Application:全局作用域,每个ServletContext生命周期内,创建新的实例(web环境中,了解)
  • websocket:HTTP WebSocket 作用域(了解)
java 复制代码
@Component
public class DogBeanConfig {
    @Bean
    public Dog dog() {
        Dog dog = new Dog();
        dog.setName("旺旺");
        return dog;
    }
    
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public Dog singleDog() {
        Dog dog = new Dog();
        return dog;
    }
    
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Dog prototypeDog() {
        Dog dog = new Dog();
        return dog;
    }
    
    @Bean
    @RequestScope
    public Dog requestDog() {
        Dog dog = new Dog();
        return dog;
    }
    
    @Bean
    @SessionScope
    public Dog sessionDog() {
        Dog dog = new Dog();
        return dog;
    }
    
    @Bean
    @ApplicationScope
    public Dog applicationDog() {
        Dog dog = new Dog();
        return dog;
    }
}
java 复制代码
@RestController
public class DogController {
    @Autowired
    private Dog singleDog;
    @Autowired
    private Dog prototypeDog;
    @Autowired
    private Dog requestDog;
    @Autowired
    private Dog sessionDog;
    @Autowired
    private Dog applicationDog;
    @Autowired
    private ApplicationContext applicationContext;

    @RequestMapping("/single")
    public String single() {
        Dog contextDog = (Dog)applicationContext.getBean("singleDog");
        return "dog:"+singleDog.toString()+",contextDog:"+contextDog;
    }

    @RequestMapping("/prototype")
    public String prototype() {
        Dog contextDog = (Dog)applicationContext.getBean("prototypeDog");
        return "dog:"+prototypeDog.toString()+",contextDog:"+contextDog;
    }

    @RequestMapping("/request")
    public String request() {
        Dog contextDog = (Dog)applicationContext.getBean("requestDog");
        return "dog:"+requestDog.toString()+",contextDog:"+contextDog.toString();
    }
    
    @RequestMapping("/session")
    public String session() {
        Dog contextDog = (Dog)applicationContext.getBean("sessionDog");
        return "dog:"+sessionDog.toString()+",contextDog:"+contextDog.toString();
    }
    
    @RequestMapping("/application")
    public String application() {
        Dog contextDog = (Dog)applicationContext.getBean("applicationDog");
        return "dog:"+applicationDog.toString()+",contextDog:"+contextDog.toString();
    }
}
  • 单例作用域:多个请求中拿到同一个对象(全部相同)
  • 多例作用域:每次拿到的都不是一个对象(每次的Dog地址都不同)
  • 请求作用域:在同一个请求中是一个对象,不同的请求中是另一组不同的对象(同一个URL访问中的适用applicationContext和@Autowired获取的Dog一样,另一个请求中是另一对一样的)
  • 会话作用域:在同一个会话中是同一个对象,不同的会话中(同一个浏览器中的两个Dog一样,不同浏览器中不一样的一对)
  • Application作用域:整个Web容器内全部相同

singleton 和 Application的区别

Application scope就是对于整个web容器来说,Bean的作⽤域是ServletContext级别的。这个和singleton有点类似,区别在于: Application scope是ServletContext的单例,singleton是⼀个ApplicationContext的单例。 在⼀个web容器中ApplicationContext可以有多个。

Bean的生命周期

Bean 的生命周期分为以下5个部分:

  • 实例化(为Bean分配内存空间)
  • 属性赋值(Bean注入和装配,比如 @AutoWired)
  • 初始化
    • 执行各种通知,如 BeanNameAware,BeanFactoryAware,ApplicationContextAware 的接口方法。
    • 执行初始化方法,包括:xml定义 init-method,使用注解的方式 @PostConstruct,执行初始化后置方法(BeanPostProcessor)
  • 使用Bean
  • 销毁Bean
    • 销毁容器的各种方法,如 @PreDestroy,DisposableBean 接口方法,destroy-method。
java 复制代码
@Component
public class BeanLifeComponent {
    public BeanLifeComponent() {
        System.out.println("执行构造函数....");
    }
    @Autowired
    public void setDog(Dog dog){
        System.out.println("执行setter方法....");
    }
    @PostConstruct
    public void init() {
        System.out.println("执行init方法....");
    }
    public void use(){
        System.out.println("执行use方法....");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行destroy方法....");
    }

}
java 复制代码
@SpringBootTest
class SpringPrincipleApplicationTests {

    @Autowired
    private BeanLifeComponent beanLifeComponent;

    @Test
    void contextLoads() {
        beanLifeComponent.use();
    }
}
相关推荐
遇见你...2 小时前
B03 SpringMVC拦截器
java·开发语言
星晨雪海2 小时前
缓存更新操作实例
java·spring·缓存
東雪木2 小时前
Java学习——接口 (interface) 与抽象类 (abstract) 的本质区别、选型标准
java·开发语言·jvm·学习·java面试
_MyFavorite_2 小时前
JAVA重点基础、进阶知识及易错点总结(16)多线程基础(Thread & Runnable)
java·开发语言
大数据新鸟2 小时前
java8基础知识--字符串
java
ChoSeitaku2 小时前
NO.2|数据结构设计|日志封装|DeepSeel接入封装|全量返回实现测试|SSE|流式响应实现测试
java·jvm·数据结构
斌味代码2 小时前
后端实战实战案例
java
小信丶2 小时前
彻底解决 IDEA 启动 SpringBoot 报错:Command line is too long
java·spring boot·intellij-idea