Deprecated: 自 6.9.0 版本起,使用参数调用函数 WP_Dependencies->add_data() 已弃用!IE conditional comments are ignored by all supported browsers. in D:\wwwroot\zyxy\wordpress\wp-includes\functions.php on line 6131

Deprecated: 自 6.9.0 版本起,使用参数调用函数 WP_Dependencies->add_data() 已弃用!IE conditional comments are ignored by all supported browsers. in D:\wwwroot\zyxy\wordpress\wp-includes\functions.php on line 6131

Spring Bean的生命周期与作用域

好的,各位观众老爷们,大家好!今天咱们来聊聊Spring Bean的生命周期和作用域,这可是Spring框架里的重头戏,也是面试官们最喜欢“调戏”候选人的地方。别怕,今天我保证把这俩玩意儿给你们讲得透透的,保管你们听完之后,见到面试官再也不发怵,还能反过来调戏他们几句!😎

开场白:Bean,你的一生,我来守护!

各位,Bean在Spring的世界里,那可是主角啊!就像演员在舞台上,有了剧本,有了导演,才能演绎出精彩的故事。而Bean就是这个故事里的演员,Spring容器就是那个舞台,负责管理Bean的生老病死,确保它能尽情地表演,完成自己的使命。

所以,了解Bean的生命周期和作用域,就相当于了解演员的一生,从出生到谢幕,每个阶段都有它的意义。只有了解这些,我们才能更好地驾驭Bean,让它为我们服务,构建出更加健壮、灵活的应用。

第一幕:Bean的生命周期——从呱呱坠地到寿终正寝

咱们先来聊聊Bean的生命周期。这玩意儿听起来玄乎,其实很简单,就是Bean从创建到销毁的整个过程。就像人的一生,有出生、成长、工作、退休、死亡,Bean也差不多,只不过它的一生更加精彩,也更加可控。

为了方便大家理解,我画了个表格,把Bean的生命周期给总结了一下:

阶段 描述 对应的方法/接口 备注
Instantiation (实例化) Spring容器根据Bean的定义(通常是配置信息)创建一个Bean的实例。就像婴儿呱呱坠地,来到了这个世界。 构造函数 这是Bean诞生的第一步,也是最重要的一步。
Populate properties (属性填充) Spring容器将Bean定义中声明的属性值注入到Bean实例中。就像给婴儿喂奶,让它茁壮成长。 Setter方法、字段注入 这是Bean成长的关键阶段,决定了Bean的初始状态。
Aware interfaces (感知接口) 如果Bean实现了某些Aware接口(例如BeanNameAwareBeanFactoryAwareApplicationContextAware),Spring容器会调用这些接口的方法,让Bean了解自己的身份和所处的环境。就像婴儿开始认识周围的世界,学习各种知识。 setBeanName()setBeanFactory()setApplicationContext() 这些接口可以让Bean更好地融入Spring容器,获取更多的资源。
Bean Post Processors before initialization (初始化前置处理) Spring容器会调用所有注册的BeanPostProcessorpostProcessBeforeInitialization()方法,对Bean进行一些预处理。就像给婴儿做体检,确保它健康成长。 postProcessBeforeInitialization() 这是一个非常强大的扩展点,可以对Bean进行各种定制化的处理。
Initialization (初始化) 如果Bean实现了InitializingBean接口,Spring容器会调用afterPropertiesSet()方法。如果Bean定义中指定了init-method属性,Spring容器也会调用该方法。就像婴儿开始学习走路说话,掌握各种技能。 afterPropertiesSet()init-method 这是Bean正式开始工作的准备阶段,可以进行一些初始化操作。
Bean Post Processors after initialization (初始化后置处理) Spring容器会调用所有注册的BeanPostProcessorpostProcessAfterInitialization()方法,对Bean进行一些后处理。就像给婴儿颁发毕业证书,祝贺它顺利毕业。 postProcessAfterInitialization() 这是一个非常强大的扩展点,可以对Bean进行各种定制化的处理。
Ready to use (可以使用) Bean已经完成了所有的初始化工作,可以被应用程序使用了。就像一个成年人,可以独立工作,为社会做贡献。 这是Bean生命周期中最长的阶段,Bean会一直存在,直到容器关闭。
Destruction (销毁) 当Spring容器关闭时,或者Bean不再需要时,Spring容器会销毁Bean。就像人去世,离开了这个世界。 DisposableBean接口的destroy()方法、destroy-method属性 这是Bean生命的终点,可以进行一些清理工作,释放资源。

怎么样,是不是感觉清晰多了?😎

重点来了!

  • BeanPostProcessor: 这是一个非常强大的接口,允许我们在Bean的初始化前后进行一些定制化的处理。比如,我们可以用它来自动注入一些依赖,或者修改Bean的属性值。

  • InitializingBean 和 DisposableBean: 这两个接口分别提供了afterPropertiesSet()destroy()方法,允许我们在Bean初始化和销毁时执行一些自定义的逻辑。

  • init-method 和 destroy-method: 除了实现接口,我们还可以通过在Bean的定义中指定init-methoddestroy-method属性,来指定初始化和销毁时要调用的方法。

举个栗子:

假设我们有一个UserService类,需要在初始化时打印一条日志,并在销毁时关闭数据库连接。我们可以这样做:

public class UserService implements InitializingBean, DisposableBean {

    private String databaseUrl;
    private Connection connection;

    public void setDatabaseUrl(String databaseUrl) {
        this.databaseUrl = databaseUrl;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("UserService initializing...");
        connection = DriverManager.getConnection(databaseUrl);
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("UserService destroying...");
        if (connection != null) {
            connection.close();
        }
    }
}

或者,我们也可以使用init-methoddestroy-method

public class UserService {

    private String databaseUrl;
    private Connection connection;

    public void setDatabaseUrl(String databaseUrl) {
        this.databaseUrl = databaseUrl;
    }

    public void init() throws Exception {
        System.out.println("UserService initializing...");
        connection = DriverManager.getConnection(databaseUrl);
    }

    public void destroy() throws Exception {
        System.out.println("UserService destroying...");
        if (connection != null) {
            connection.close();
        }
    }
}

然后在Spring配置文件中这样配置:

<bean id="userService" class="com.example.UserService" init-method="init" destroy-method="destroy">
    <property name="databaseUrl" value="jdbc:mysql://localhost:3306/mydb"/>
</bean>

第二幕:Bean的作用域——你在哪儿,我才能找到你!

聊完了生命周期,咱们再来看看Bean的作用域。作用域决定了Bean的可见性和生命周期。就像演员在舞台上的位置,决定了观众能否看到他,以及他能表演多久。

Spring提供了多种作用域,常用的有以下几种:

作用域 描述 备注
singleton (单例) 在整个Spring容器中,只有一个Bean的实例。就像一个剧团只有一个主角,所有人都围着他转。 这是默认的作用域,适用于无状态的Bean。
prototype (原型) 每次请求Bean时,Spring容器都会创建一个新的Bean实例。就像每次演出都会换一批群众演员,每个人都是全新的。 适用于有状态的Bean,每个请求都需要独立的实例。
request (请求) 每次HTTP请求都会创建一个新的Bean实例。就像每个观众都有自己的专属座位,互不干扰。 只能在Web应用中使用。
session (会话) 每次HTTP会话都会创建一个新的Bean实例。就像每个包间都有自己的专属服务员,只服务于该包间的客人。 只能在Web应用中使用。
application (应用) 在整个Web应用中,只有一个Bean的实例。就像一个剧院只有一个经理,负责管理整个剧院的运作。 只能在Web应用中使用。
websocket (WebSocket) 每次WebSocket会话都会创建一个新的Bean实例。 只能在Web应用中使用,且需要支持WebSocket。

重点来了!

  • singleton vs prototype: 这是最常用的两种作用域,也是面试官最喜欢问的。记住,singleton是单例,prototype是原型,两者之间最大的区别在于实例的创建时机和生命周期。

  • Web相关的作用域: request、session、application和websocket只能在Web应用中使用,它们与HTTP请求、会话和应用的生命周期密切相关。

举个栗子:

假设我们有一个Counter类,用于记录访问次数。如果我们将它设置为singleton作用域,那么所有的请求都会共享同一个Counter实例,访问次数会不断累加。

public class Counter {

    private int count = 0;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}
<bean id="counter" class="com.example.Counter" scope="singleton"/>

但是,如果我们将它设置为prototype作用域,那么每次请求都会创建一个新的Counter实例,每个请求都会从0开始计数。

<bean id="counter" class="com.example.Counter" scope="prototype"/>

第三幕:实战演练——如何优雅地使用Bean的生命周期和作用域

理论学完了,咱们来点实际的。下面我给大家分享一些使用Bean的生命周期和作用域的最佳实践。

  • 使用构造函数注入依赖: 尽量使用构造函数注入依赖,而不是Setter方法或字段注入。这样可以确保Bean在创建时就拥有了所有的依赖,避免了空指针异常。

  • 使用InitializingBean和DisposableBean接口: 如果需要在Bean初始化和销毁时执行一些自定义的逻辑,可以使用这两个接口。但是,如果逻辑比较简单,可以使用init-methoddestroy-method属性。

  • 谨慎使用BeanPostProcessor: 虽然BeanPostProcessor非常强大,但是使用不当可能会导致一些意想不到的问题。所以,在使用时一定要小心,确保你的逻辑是正确的。

  • 选择合适的作用域: 根据Bean的状态和使用场景,选择合适的作用域。对于无状态的Bean,可以使用singleton作用域。对于有状态的Bean,可以使用prototype作用域。对于Web应用,可以使用request、session、application和websocket作用域。

总结:Bean,你就是我的小星星!

好了,各位观众老爷们,今天关于Spring Bean的生命周期和作用域的讲解就到这里了。希望通过今天的讲解,大家对这两个概念有了更深入的理解。记住,Bean是Spring框架的核心,了解它的生命周期和作用域,才能更好地驾驭它,构建出更加健壮、灵活的应用。

最后,我想用一句歌词来总结一下:Bean,你就是我的小星星,照亮我前进的方向!✨

希望这篇文章对大家有所帮助!如果大家还有什么问题,欢迎在评论区留言,我会尽力解答。谢谢大家!👏

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注