springboot bean生命周期和作用域

springboot bean生命周期和作用域

在Spring的IoC(控制反转)和DI(依赖注入)机制中,Spring框架提供了工具来帮助我们管理对象及其依赖关系。Spring通过注解来声明Bean对象,这样更加简洁且易于维护。以下是常用的注解及其用途:

1.Spring对象的控制

1.1.声明Bean对象

  • @Controller通常用于标识Web控制器类;
  • @Service用于业务逻辑层;
  • @Repository用于数据访问层。
    上面三个注解都包含@Component注解,这意味着它们都可以被组件扫描自动检测并注册为Spring容器中的Bean。
  • @Component:这是一个通用的注解,用于标记任何Spring管理的组件。允许Spring通过组件扫描机制自动发现并注册到应用上下文中。
  • @Configuration:这个注解用于定义一个配置类,其中可以使用@Bean注解的方法来定义Spring管理的bean。配置类本身也是一个Spring bean。
  • @Bean:在配置类内部使用,用来显式声明一个或多个方法返回的对象应由Spring容器管理。通常与@Configuration一起使用。

1.2.获取对象

Spring提供了两种主要的方式来获取Spring管理的Bean实例:

  • ApplicationContext:这是Spring的核心接口之一,它扩展了BeanFactory的功能,增加了事件发布、国际化支持等功能。常见的实现包括ClassPathXmlApplicationContext, AnnotationConfigApplicationContext等。通过ApplicationContext获取Bean的方式非常直观,例如:

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyBean myBean = context.getBean(MyBean.class);
  • BeanFactory:这是Spring IoC容器的基础接口,提供了基本的DI功能。相比ApplicationContext,它不支持基于注解的配置,也不提供一些高级特性如AOP代理等。

1.3. 依赖注入

Spring提供了多种方式进行依赖注入

  • @Autowired:最常用的注解之一,可用于构造器、字段以及setter方法上。可以自动装配依赖项,无需手动查找和创建依赖对象。
@Service
public class MyService {
    private final MyDependency myDependency;

    @Autowired // 构造器注入
    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }
}
  • Setter方法注入:除了构造器注入外,还可以通过setter方法进行依赖注入。这种方式允许在对象创建后动态改变依赖关系,但不如构造器注入安全。
@Service
public class MyService {
    private MyDependency myDependency;

    @Autowired
    public void setMyDependency(MyDependency myDependency) {
        this.myDependency = myDependency;
    }
}

构造函数注入:推荐的方式,在需要不可变属性的情况下。使得对象一旦创建就处于完全初始化状态,并且避免了潜在的空指针异常问题。

2.Spring Boot Bean 作用域

2.1.Spring支持多种不同的Bean作用域,默认的是singleton。

以下是几种常见的作用域:

  • Singleton:默认的作用域,在整个应用上下文中只会存在一个实例。适用于无状态的服务类对象。
  • Prototype:每次请求都会创建一个新的实例。适合有状态的对象。
  • Request:每个HTTP请求都会有单独的Bean实例,仅适用于Web应用。
  • Session:每个HTTP会话都会有单独的Bean实例,同样只适用于Web应用。
  • Application:在整个ServletContext范围内有效,类似于Servlet API中的ServletContext属性。

2.2.Spring Boot Bean的作用域决定了Bean的生命周期和可见性范围。

以下是几种主要作用域的区别:

  • Singleton(单例):
    默认作用域:每个Spring IoC容器中仅存在一个实例。
    适用场景:适用于无状态的Bean,如服务层对象或DAO层对象。
    特点:所有对该Bean的请求都会返回同一个实例,因此在多线程环境下需要注意线程安全问题。
  • Prototype(原型):
    每次获取都会创建新实例:每次通过容器请求该Bean时,都会创建一个新的实例。
    适用场景:适用于有状态的Bean,例如需要独立状态的对象。
    特点:由于每次都创建新实例,因此不支持销毁方法,也无法利用Spring容器管理Bean的完整生命周期。
  • Request(请求):
    每个HTTP请求对应一个实例:在Web应用中,为每个HTTP请求创建一个Bean实例,在请求完成后实例被丢弃。
    适用场景:适用于需要保持请求间数据隔离的场景。
    特点:仅在基于Web的Spring ApplicationContext实现中有效。
  • Session(会话):
    每个HTTP会话对应一个实例:在Web应用中,为每个HTTP会话创建一个Bean实例,在会话结束后实例被销毁。
    适用场景:适合需要跨多个请求共享数据的情况。
    特点:同样,只在基于Web的Spring ApplicationContext实现中有效。
  • Application(应用程序):
    整个ServletContext范围内有效:在Web应用中,为整个ServletContext创建一个Bean实例,类似于Servlet API中的ServletContext属性。
    适用场景:适用于需要在整个Web应用中共享的数据。
    特点:与Singleton类似,但其作用范围限定于Web应用的ServletContext。

2.3.示例

其中单列作用域和原型作用域使用@scope注解,其余作用域使用对应名字的注解。或者使用下面样式
@Scope(value =WebApplicationContext.SCOPE_REQUEST, proxyMode =
ScopedProxyMode.TARGET_CLASS)

  • Singleton(单例)
@Component
@Scope("singleton") // 默认,可以省略
public class SingletonBean {
    public void sayHello() {
        System.out.println("Singleton: Hello from SingletonBean");
    }
}
  • Prototype(原型)
@Component
@Scope("prototype")
public class PrototypeBean {
    public void sayHello() {
        System.out.println("Prototype: Hello from PrototypeBean");
    }
}
  • Request(请求)
    为了演示Request,需要一个Web应用环境
@Component
@RequestScope
public class RequestBean {
    private final HttpServletRequest request;

    public RequestBean(HttpServletRequest request) {
        this.request = request;
    }

    public void sayHello() {
        System.out.println("Request: Hello from RequestBean, Request ID: " + request.hashCode());
    }
}

Controller使用这个Bean:

@RestController
public class RequestController {

    @Autowired
    private RequestBean requestBean;

    @GetMapping("/request")
    public String getRequestMessage() {
        requestBean.sayHello();
        return "Check console for output";
    }
}
  • Session(会话)
    类似于Request作用域
@Component
@SessionScope
public class SessionBean {
    private final HttpSession session;

    public SessionBean(HttpSession session) {
        this.session = session;
    }

    public void sayHello() {
        System.out.println("Session: Hello from SessionBean, Session ID: " + session.getId());
    }
}

Controller使用这个Bean:

@RestController
public class SessionController {

    @Autowired
    private SessionBean sessionBean;

    @GetMapping("/session")
    public String getSessionMessage() {
        sessionBean.sayHello();
        return "Check console for output";
    }
}
  • Application(应用程序)
@Component
@ApplicationScope
public class ApplicationBean {
    private final ServletContext servletContext;

    public ApplicationBean(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    public void sayHello() {
        System.out.println("Application: Hello from ApplicationBean, Context Path: " + servletContext.getContextPath());
    }
}

使用该Bean的Controller:

@RestController
public class ApplicationController {

    @Autowired
    private ApplicationBean applicationBean;

    @GetMapping("/application")
    public String getApplicationMessage() {
        applicationBean.sayHello();
        return "Check console for output";
    }
}

3.Spring Boot Bean 生命周期

Spring Boot Bean的生命周期是Spring框架中一个核心概念,它定义了从Bean的创建到销毁过程中所经历的不同阶段。理解 Bean的生命周期这些阶段有助于更好地设计和实现基于Spring的应用程序

3.1.步骤

  • 实例化:创建Bean的实例。
    Spring容器根据Bean的定义信息(如XML配置、注解或Java配置)创建Bean的实例。

  • 属性填充:设置Bean的属性值。
    Spring将配置文件中定义的属性值赋给Bean实例。如:通过构造器注入、setter方法注入或其他方式注入的

  • 初始化前回调:调用Aware接口的方法和BeanPostProcessor的前置处理。
    如果bean实现了BeanNameAware(设置Bean名称),BeanFactoryAware(创建该Bean的BeanFactory的引用) 则会执行

  • 初始化:调用InitializingBean的afterPropertiesSet()方法或自定义初始化方法。
    如果bean实现了InitializingBean接口,则会调用其afterPropertiesSet()方法,另外可以通过@PostConstruct注解或在配置文件中指定init-method来定义自己的初始化方法。

  • 初始化后回调:调用BeanPostProcessor的后置处理。
    允许在初始化方法前后调用自定义BeanPostProcessor#postProcessBeforeInitialization在初始化之前执行的逻辑和BeanPostProcessor#postProcessAfterInitialization在初始化之后执行的逻辑

  • 使用:Bean准备就绪,可以被应用程序使用。

  • 销毁:调用DisposableBean的destroy()方法或自定义销毁方法。
    如果Bean实现了DisposableBean接口,则会调用其destroy()方法。另外也可通过在配置文件中指定destroy-method来定义自己的销毁方法

3.2.bean生命周期演示

  • 定义bean
//bean1
@Component
public class MyDependency {
   

    public MyDependency() {
   
        System.out.println("MyDependency created");
    }
}
//bean2

@Component
public class MyBean implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware {
   
    private MyDependency myDependency;
    private String someProperty = "TEST";

    private String beanName;
    private BeanFactory beanFactory;
    public String getSomeProperty() {
   
        return someProperty;
    }

    public void setSomeProperty(String someProperty) {
   
        this.someProperty = someProperty;
    }

    @Autowired
    public MyBean(MyDependency myDependency) {
   
        this.myDependency = myDependency;
        System.out.println("属性填充: " + myDependency);
    }

    @PostConstruct
    public void init() {
   
        System.out.println("PostConstruct 自定义初始化方法调用");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
   
        System.out.println("InitializingBean.afterPropertiesSet() 调用");
    }
    //DisposableBean接口:如果实现了DisposableBean接口,则会调用其destroy()方法
    @Override
    public void destroy() throws Exception {
   
        System.out.println("DisposableBean.destroy() 调用");
    }

    //BeanNameAware:设置Bean名称。
    @Override
    public void setBeanName(String name) {
   
        this.beanName = name;
        System.out.println</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值