亲宝软件园·资讯

展开

Bean作用域和生命周期

富春山居_ZYY 人气:0

一、Bean 的作用域

在之前学习Java基础的时候,有接触到作用域这样的概念。一个变量并不一定在任何区域都是有效的,限定这个变量的可用性的代码范围就是该变量的作用域。

但是在这里 Bean 的作用域的概念和以前所认为的作用域有所不同。

Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。

接下来,将会举一个案例来讲讲什么是作用域,什么是行为模式

案例概要:

创建一个共有的 Bean ,使用者A和使用者B都对该 Bean 进行了使用

使用者A在进行使用的时候,创建一个新的变量接收注入进来的 Bean,进行修改,将修改后的结果进行返回;

使用者B 直接将注入进来的 Bean 进行返回,不进行任何操作

代码实现:

步骤一:创建出一个公共的 Bean

@Component
public class UserComponent {
    @Bean
    public User getUser() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassWord("111111");
        return user;
    }
}

步骤二:使用者A获取到公共 Bean,进行修改

@Controller
public class UserControllerA {
    @Autowired
    private User user;
    public User getUser1() {
        System.out.println("使用者A拿到的原始user:" + user);
        User myUser = user;
        myUser.setName("李四");
        return myUser;
    }
}

步骤三:使用者B直接将获取到的公共的 Bean 进行返回

@Controller
public class UserControllerB {
    @Autowired
    private User user;
    public User getUser2() {
        return user;
    }
}

步骤四:main 中获取 UserControllerA 类和 UserControllerB 类使用查看

public class Start {
    public static void main(String[] args) {
        //获取 Spring 上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //获取到Spring容器中的 UserControllerA 类(Bean 对象)
        UserControllerA userControllerA = context.getBean("userControllerA",UserControllerA.class);
        //使用 Bean 对象
        System.out.println("使用者A->"+userControllerA.getUser1());
		//获取到Spring容器中的 UserControllerA 类(Bean 对象)
        UserControllerB userControllerB = context.getBean("userControllerB",UserControllerB.class);
        //使用 Bean 对象
        System.out.println("使用者B->"+userControllerB.getUser2());
    }
}

预期结果:

使用者 A修改后,其结果是修改过的;使用者 B 没有修改过,其结果应该和原始user一样

结果显示:

和预期结果有所不同,使用者 A 和使用者 B 所得到的结果都是被修改过的。

这是因为在 Spring 中,Bean 默认情况下是单例状态,大家用的都是同一份对象,是全局共享的,当有其他人修改了该对象,另一个人所获取到的对象就是被修改过的,这便是 Bean 六大作用域之一——单例作用域(singleton)

在写 WEB 项目的时候,我们知道 DataSource 就是单例模式,使用单例,好处多多,可以确保所有对象都访问唯一实例,而且减少了内存的开支和系统性能的开销,因此 Bean 默认情况下是单例状态。

若想要按照预期结果输出,就需要将 Bean 的作用域设置成原型作用域,即无论谁来使用 Bean 对象,获取到的都是原始的 Bean 对象,大家各玩各的。

需要在注入的对象上使用注解修改作用域,有以下两种方法(Scope就是作用域的意思)

@Component
public class UserComponent {
    //@Scope("prototype")    //方法一
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //方法二
    @Bean
    public User getUser() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassWord("111111");
        return user;
    }
}

Bean 的 6 种作用域

singleton:单例作用域

prototype:原型作⽤域/多例作⽤域

request:请求作用域

session:会话作用域

application:全局作用域

websocket: HTTP WebSocket 作⽤域(不常用)

单例作用域和全局作用域比较像,但全局作用域范围没有单例作用域大,前者是 Spring 核心的作用域,后者是 Spring Web 中的作用域,前者作用于 IoC 容器,后者作用于 Servlet 容器

二、Spring 的执行流程

Spring 的执行流程也可以说是 Bean的执行流程,主要分成4部分

三、Bean 的生命周期

Bean 的生命周期即 Bean 从诞生到销毁的整个过程

实例化 Bean 对象,申请内存空间

设置 Bean 的属性,进行依赖注入和装配

Bean 的初始化

使用 Bean

销毁 Bean

补充

实例化和初始化的区别

@PostConstructor 和 @PreDestroy 是注解方式进行初始化和注销,init-method 和 destroy-method 是 XML 方法进行初始化和注销,一般只要使用其中的一种进行初始化

设置属性一定要在初始化之前,因为初始化也可能需要使用到注入的对象,如果没有进行属性的设置,初始化就会出现问题

案例:生命周期演示

@Component
public class BeanLife implements BeanNameAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("BeanName 感知:"+ s);
    }
    @PostConstruct
    public void postConstructor() {
        System.out.println("执行初始化方法:PostConstructor");
    }
    @PreDestroy
    public void preDestroy() {
        System.out.println("执行销毁方法:PreDestroy");
    }
    public void initMethod() {
        System.out.println("执行初始化方法:init-method");
    }
    public void destroyMethod() {
        System.out.println("执行销毁方法:destroy-method");
    }
}

XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 配置一下:bean注解扫描的根路径(方面后面更简单存储对象到spring容器)-->
    <content:component-scan base-package="com.bit.beans"></content:component-scan>
    <beans>
        <bean id="beanLife" class="com.bit.beans.Component.BeanLife" init-method="initMethod"
        destroy-method="destroyMethod"></bean>
    </beans>
</beans>

调用

public class Start {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new
                ClassPathXmlApplicationContext("spring.xml");
        BeanLife beanLife = context.getBean("beanLife",BeanLife.class);
        System.out.println("---使用 Bean 对象---");
        System.out.println("---注销 Bean 对象--- ");
        context.destroy();//容器的销毁相当于销毁所有的 Bean
    }
}

结果显示:

流程图展示:

加载全部内容

相关教程
猜你喜欢
用户评论