> 文章列表 > 【JavaEE】Bean的作用域和生命周期

【JavaEE】Bean的作用域和生命周期

【JavaEE】Bean的作用域和生命周期

目录

Bean的作用

作用域分类

设置作用域

通过注解设置

通过配置文件设置

Bean的生命周期


Bean的作用域

Bean的作用域是指:在整个Spring容器中Bean的行为模式。这个模式有六种。

作用域分类

  1. singleton:单例作用域

    在这个模式下,容器一启动就会创建出一个实例化的Bean对象,后续使用它时,都是直接对它进行操作,直到最后容器销毁Bean才会销毁。

    适用于Bean状态不需要更新的情况。

  2. prototype:原型作用域(多例作用域)。

    在这个模式下,只要请求Bean,Spring都会创建出一个新的实例返回,当实例使用完成后就会自动销毁。

    适用于Bean状态需要更新的情况。

    以下三种只适用于Spring MVC

  3. request:请求作用域。

    每个HTTP请求(request)中只有一个实例化的Bean对象。同一个请求中的所有处理都共享该Bean实例。该作用域下的Bean会在每个请求(request)中被创建,当请求结束时被销毁。

  4. session:会话作用域。

    每个HTTP会话(session)中只有一个实例化的Bean对象。同一个会话中所有的请求都共享该Bean实例。该作用域下的Bean会在每个会话(session)中被创建,当会话结束时被销毁。

  5. application:全局作用域。

    所有Web应用中只有一个实例化的Bean对象,同一个Web应用中的所有请求都共享该Bean实例。该作用域下的Bean会在Web应用启动时被创建,当Web应用关闭时被销毁。

    和singleton的区别

    1. singleton是Spring Core的作用域,application是Spring MVC的
    2. singleton是作用于IoC容器,application是作用于Servlet容器
  6. websocket:HTTP WebSocket作用域。

    在一个HTTP WebSocket的生命周期中,定义一个实例。
    只能在HTTP WebSocket中使用。

由于我们目前的项目是Spring Core项目,目前只可以演示单例作用域和原型作用域。现在来演示一下单例作用域的效果。

package com.test.entity;import lombok.Getter;
import lombok.Setter;
import lombok.ToString;@Setter
@Getter
@ToString
public class User {private Integer id;private String name;
}
package com.test.repository;import com.test.entity.User;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;@Repository
public class BuildUser {@Beanpublic User user() {User user = new User();user.setId(1);user.setName("张三");return user;}
}

这里使用方法注解把User存到了Spring容器中。 接下来使用Controller从Spring获取到User,然后修改名字。最后Service从Spring中获取到User,查看是否和最开始的User一样。

package com.test.controller;import com.test.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {@Autowiredprivate User user;public User getUser() {User user1 = user;user1.setName("李四");return user1;}
}
package com.test.service;import com.test.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate User user;public User getUser() {User user1 = user;return user1;}
}

最后打印一下User,看看是否符合单例的模式。

import com.test.controller.UserController;
import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");User user1 = context.getBean("user", User.class);System.out.println("直接拿最开始存的User:" + user1.toString());UserController userController = context.getBean("userController", UserController.class);System.out.println("在UserController修改后返回的User:" + userController.getUser().toString());UserService userService = context.getBean("userService", UserService.class);System.out.println("在UserService中得到开始的User:" + userService.getUser().toString());}
}


设置作用域

默认的作用域是单例作用域,当我们想要更改其作用域是,通过注解和配置文件的方式更改。建议使用注解的方式

通过注解设置

@Scope  使用这个注解来改变当前bean的作用域。

需要设置在其他注解的上面,因为一开始就要确认其存储方法

有两种方法可以设置,推荐第一种

  1. @Scope("在这里设置作用域")  比如 @Scope("ConfigurableBeanFactory.SCOPE_PROTOTYPE")  这个类中的常量是给我们设置好了,这样可以防止拼错
  2. @Scope("在这里设置作用域")  比如
    @Scope("prototype")  这样需要自己拼写,容易拼错。

把上述的Bean从单例作用域变成原型作用域。

package com.test.repository;import com.test.entity.User;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;@Repository
public class BuildUser {@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@Beanpublic User user() {User user = new User();user.setId(1);user.setName("张三");return user;}
}

通过配置文件设置

这里需要到配置文件中修改 bean 属性scope

    <bean id="buildBean" class="com.test.repository.BuildUser" scope="prototype"></bean>

效果同上。

如果二者同时设置了,并且有冲突,注解的方法优先级高于配置文件。 


Bean的生命周期

Bean的生命周期主要有五大部分。

  1. 实例化Bean:为Bean分配空间
  2. 设置属性:在Bean的注入和装配时需要设置属性
  3. Bean初始化
    1. 实现各种Aware通知方法
      BeanNameAware、BeanFactoryAware、ApplicationContextAware的接口方法
    2. 执行BeanPostProcessor初始化前置方法
    3. 执行PostConstruct初始化方法,在依赖注入后实现
    4. 执行用户自己指定的init-method(如果有)
    5. 执行BeanPostProcessor初始化后置⽅法
  4. 使用Bean
  5. 销毁Bean
    销毁容器的各种⽅法,如 PreDestroy、DisposableBean 接⼝⽅法、destroy-method
package com.test.controller;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Controller;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Controller
public class BeanLifeController implements BeanNameAware, BeanPostProcessor {@Overridepublic void setBeanName(String s) {System.out.println("执行了通知Bean" + s);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("执行了postProcessAfterInitialization方法");return bean;}public void myInit() {System.out.println("执行了XML的初始化方法");}@PostConstructpublic void doConstruct() {System.out.println("执行了使用注解的初始化方法");}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("执行了postProcessBeforeInitialization方法");return bean;}public void sayHi() {System.out.println("你好");}@PreDestroypublic void doPreDestroy() {System.out.println("执行了销毁Bean容器的方法");}}

还有一些存Bean的代码不作展示了。

import com.test.controller.BeanLifeController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BeanLifeController beanLifeController = context.getBean("beanLifeController", BeanLifeController.class);beanLifeController.sayHi();beanLifeController.doPreDestroy();}
}

其中初始化使用了两种方式实现:


有什么错误评论区指出,希望可以帮到你。

全国邮编查询网