欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Spring入门-01】Bean

程序员文章站 2022-07-12 15:35:22
...

Spring Bean

作用域

  • singleton:一个 Bean 容器中只存在一个实例(Spring 默认作用域)
  • prototype:每次注入或者通过 Spring 应用上下文获取时都会创建一个单独的实例
  • request:每个 request 请求都会创建一个单独的实例
  • session:每个 session 都会创建一个单独的实例
  • application:每个 servletContext 都会创建一个单独的实例
  • websocket:每个 websocket 都会创建一个单独的实例
  • simpleThreadScope:每个线程都会创建一个单独的实例

singleton

使用 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) 注解标注 Bean 的作用域为 singleton ,则每次注入的 bean 都是同一个实例。

  • JavaConfig
@Configuration
public class ScopeBeanConfig {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public SingletonBean singletonBean() {
        return new SingletonBean();
    }
}

public class SingletonBean {
}
  • XML 配置
    <bean class="SingletonBean" scope="singleton"/>

prototype

使用 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 注解标注 Bean 的作用域为 prototype ,则每次注入或从 Spring 应用上下文获取的 bean 都会创建一个新的实例。

  • JavaConfig
@Configuration
public class ScopeBeanConfig {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }
}

public class PrototypeBean {
}
  • XML 配置
    <bean class="PrototypeBean" scope="prototype"/>

request

使用 @RequestScope 注解标注 Bean 的作用域为 request ,则每次 request 请求的 bean 都会创建一个新的实例。

  • JavaConfig
@Configuration
public class ScopeBeanConfig {

    @Bean
    @RequestScope
    public RequestBean requestBean() {
        return new RequestBean();
    }
}

public class RequestBean {
}
  • XML 配置
    <bean class="RequestBean" scope="request"/>

session

使用 @SessionScope 注解标注 Bean 的作用域为 session ,则会为每个 session 创建一个新的 bean 实例。

  • JavaConfig
@Configuration
public class ScopeBeanConfig {

    @Bean
    @SessionScope
    public SessionBean sessionBean() {
        return new SessionBean();
    }
}

public class SessionBean {
}
  • XML 配置
    <bean class="SessionBean" scope="session"/>

作用域代理

request/session 作用域的 bean(cart) 注入到 singleton 作用域的 bean(storeService) 时


@Configuration
public class ScopeBeanConfig {

    @Bean
    @SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
    public Cart cart(){
        return new ShoppingCart();
    }

    @Bean
    public StoreService storeService(){
        return new StoreServiceImpl();
    }
}

public interface Cart {
}

public class ShoppingCart implements Cart {
}

public interface StoreService {
    void add();
}

public class StoreServiceImpl implements StoreService {

    @Autowired
    private Cart cart;

    @Override
    public void add() {
        System.out.println(cart.toString());
    }
}

singleton 作用域的 StoreService 在 Spring 应用上下文加载时实例化,同时试图将 Cart 构造注入。但是 session 作用域的 Cart 直到创建会话 session 后才会实例化。因此,Spring 会注入一个 Cart 的代理(暴露 Cart 中定义的方法),当 StoreService 调用 Cart 的方法时,代理会对其进行懒解析并调用委托给 session 作用域内真正的 Cart 。

通过 proxyMode 属性指定代理方式:

  • ScopedProxyMode.INTERFACES:基于 JDK 动态接口代理
  • ScopedProxyMode.TARGET_CLASS :基于 CGLib 代理

懒加载

Spring 容器会在创建容器时提前初始化 singleton 作用域的 Bean。但是如果 Bean 被标注了 lazy-init="true" ,则该 Bean 只有在其被需要的时候才会被初始化。

懒加载只对 singleton 作用域的 Bean 有效。
优点:节省资源
缺点:导致操作的响应时间增加

生命周期

初始化

如果需要在 Bean 实例化之后执行逻辑:

  1. 使用 init-method
public class Bean {
  public void init() {
    // To do
  }
}

通过 XML 配置

<bean class="Bean" init-method="init"/>

通过 JavaConfig

    @Bean(initMethod = "init")
    public Bean bean() {
        return new Bean();
    }
  1. 让 Bean 实现 org.springframework.beans.factory. InitializingBean 接口,覆盖 afterPropertiesSet 方法
public class Bean implements InitializingBean {
  @Override
  public void afterPropertiesSet() throws Exception {
    // To do
  }
}

销毁

如果需要在 Bean 销毁之前执行逻辑:

  1. 使用 destroy-method
public class Bean {

  public void destroy() {
    //To do
  }
}

通过 XML 配置

<bean class="Bean" init-method="destroy"/>

通过 JavaConfig

    @Bean(destroyMethod = "destroy")
    public Bean bean() {
        return new Bean();
    }
  1. 让 Bean 实现 org.springframework.beans.factory.DisposableBean 接口,覆盖 destroy 方法
public class Bean implements DisposableBean {
  @Override
  public void destroy() throws Exception {
    //To do
  }
}

配置全局默认初始化、销毁方法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd"

     default-init-method="init" default-destroy-method="destroy">

</beans>

Bean 后置处理器

如果想在 Spring IoC 容器完成 Bean 实例化、配置及初始化方法前后添加逻辑处理,可通过实现 BeanPostProcessor 接口定义的回调方法。此外,还可以通过实现 Ordered 接口提供的 order 属性来控制这些实现了 BeanPostProcessor 接口 Bean 后置处理器的执行顺序。

@Component
public class PostProcessor1 implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后置处理器1 before initialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后置处理器1 after initialization");
        return bean;
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
@Component
public class PostProcessor2 implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后置处理器2 before initialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后置处理器2 after initialization");
        return bean;
    }

    @Override
    public int getOrder() {
        return 2;
    }
}
    <bean class="PostProcessor1"/>
    <bean class="PostProcessor2"/>

参考

  1. GitHub 代码
  2. Spring框架小白的蜕变
  3. Spring 实战(第4版)

上一篇: Spring入门_01

下一篇: AWK 用法总结