Spring Bean的作用域与生命周期

spring容器的bean什么时候被实例化

BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化
ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:
如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则 ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使 用该 Bean的时候,直接从这个缓存中取
如果bean的scope是singleton的,并且lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化。
如果bean的scope是prototype的,则该Bean的实例化是在第一次使用该Bean的时候进行实例化。

Bean类的配置项

Spring IOC容器管理Bean时,需要了解Bean的类名、名称、依赖项、属性、生命周期及作用域等信息。为此,Spring IOC提供了一系列配置项,用于Bean在IOC容器中的定义。
① class
该配置项是强制项,用于指定创建Bean实例的Bean类的路径。
② name
该配置项是强制项,用于指定Bean唯一的标识符,在基于 XML 的配置项中,可以使用 id和或 name 属性来指定 Bean唯一 标识符。
③ scope
该配置项是可选项,用于设定创建Bean对象的作用域。
④ constructor-arg
该配置项是可选项,用于指定通过构造函数注入依赖数据到Bean。
⑤ properties
该配置项是可选项,用于指定通过set方法注入依赖数据到Bean。
⑥ autowiring mode
该配置项是可选项,用于指定通过自动依赖方法注入依赖数据到Bean。
⑦ lazy-initialization mode
该配置项是可选项,用于指定IOC容器延迟创建Bean,在用户请求时创建Bean,而不要在启动时就创建Bean。

Spring Bean的作用域(scope配置)

在Spring配置文件定义Bean时,通过声明scope配置项,可以灵活定义Bean的作用范围。
① singleton
IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
② prototype
IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
③ request
每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
④ session
该属性仅用于HTTP Session,同一个Session共享一个Bean实例。
⑤ global-session
该属性仅用于HTTP Session,所有的Session共享一个Bean实例。

Spring加载流程

初始化环境—>加载配置文件—>实例化Bean—>调用Bean显示信息
核心步骤
(1)首先是先从AbstractBeanFactory中去调用doGetBean(name, requiredType, final Object[] args, boolean typeCheckOnly)typeCheckOnly,判断进行创建bean还是仅仅用来做类型检查
(2)然后接着是去调用getSingleton()方法,用于单例Bean之间的循环依赖的解决,

singletonObjects指单例对象的cache (一级缓存)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

singletonFactories指单例对象工厂的cache(三级缓存)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

earlySingletonObjects指提前曝光的单例对象的cache(二级缓存)
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

(3)对从缓存中拿到的bean其实是最原始的bean,还未长大,所以这里还需要调用getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)方法去进行实例化。
(4)然后会解决单例情况下尝试去解决循环依赖,如果isPrototypeCurrentlyInCreation(beanName)返回为true的话,会继续下一步,否则throw new BeanCurrentlyInCreationException(beanName);
(5)因为第三步中缓存中如果没有数据的话,就直接去parentBeanFactory中去获取bean,然后判断containsBeanDefinition(beanName)中去检查已加载的XML文件中是否包含有这样的bean存在,不存在的话递归去getBean()获取,如果没有继续下一步
(6)这一步是吧存储在XML配置文件中的GernericBeanDifinition转换为RootBeanDifinition对象。这里主要进行一个转换,如果父类的bean不为空的话,会一并合并父类的属性
(7)这一步核心就是需要跟这个Bean有关的所有依赖的bean都要被加载进来,通过刚刚的那个RootBeanDifinition对象去拿到所有的beanName,然后通过registerDependentBean(dependsOnBean, beanName)注册bean的依赖
(8)然后这一步就是会根据我们在定义bean的作用域的时候定义的作用域是什么,然后进行判断在进行不同的策略进行创建(比如isSingleton、isPrototype)
(9)这个是最后一步的类型装换,会去检查根据需要的类型是否符合bean的实际类型去做一个类型转换。Spring中提供了许多的类型转换器

Spring Bean的生命周期

在这里插入图片描述
如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:

1.Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
2.Bean实例化后对将Bean的引入和值注入到Bean的属性中
3.如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
4.如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
5.如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
6.如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
7.如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
8.如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
9.Bean已经准备就绪,如果scope设置singleon,缓存在springioc容器。如果为prototype生命周期交给应用程序。
10.如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法
11.如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

Bean 的生命周期验证

public class Book implements BeanNameAware,BeanFactoryAware,
        ApplicationContextAware,InitializingBean,DisposableBean {

    private String bookName;
    public Book(){
        System.out.println("Book Initializing ");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Book.setBeanFactory invoke");
    }

    public void setBeanName(String name) {
        System.out.println("Book.setBeanName invoke");
    }

    public void destroy() throws Exception {
        System.out.println("Book.destory invoke");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Book.afterPropertiesSet invoke");
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("Book.setApplicationContext invoke");
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
        System.out.println("setBookName: Book name has set.");
    }

    public void myPostConstruct(){
        System.out.println("Book.myPostConstruct invoke");
    }

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

    public void myPreDestory(){
        System.out.println("Book.myPreDestory invoke");
        System.out.println("---------------destroy-----------------");
    }

    // 自定义销毁方法
    @PreDestroy
    public void springPreDestory(){
        System.out.println("@PreDestory");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("------inside finalize-----");
    }
}

自定义实现BeanPostProcessor 的MyBeanPostProcessor:

public class MyBeanPostProcessor implements BeanPostProcessor {

    // 容器加载的时候会加载一些其他的bean,会调用初始化前和初始化后方法
    // 这次只关注book(bean)的生命周期
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Book){
            System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Book){
            System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
        }
        return bean;
    }
}

在resources 目录下新建Bean-Lifecycle.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

      <!-- 扫描bean -->
    <context:component-scan base-package="com.bean.lifecycle"/>

    <!-- 实现了用户自定义初始化和销毁方法 -->
    <bean id="book" class="com.bean.lifecycle.Book" init-method="myPostConstruct" destroy-method="myPreDestory">
          <!-- 注入bean 属性名称 -->
        <property name="bookName" value="thingking in java" />
    </bean>

      <!--引入自定义的BeanPostProcessor-->
    <bean class="com.bean.lifecycle.MyBeanPostProcessor"/></beans>

做一个启动类的测试,新建SpringBeanLifecycleApplication

public class SpringBeanLifecycleApplication {

    public static void main(String[] args) throws InterruptedException {
        // 为面试而准备的Bean生命周期加载过程
        ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
        Book book = (Book)context.getBean("book");
        System.out.println("Book name = " + book.getBookName());
        ((ClassPathXmlApplicationContext) context).destroy();

    }

}

输出结果

Book Initializing 
setBookName: Book name has set.
Book.setBeanName invoke
Book.setBeanFactory invoke
Book.setApplicationContext invoke
MyBeanPostProcessor.postProcessBeforeInitialization
@PostConstruct
Book.afterPropertiesSet invoke
Book.myPostConstruct invoke
MyBeanPostProcessor.postProcessAfterInitialization
Book name = thingking in java

@PreDestory
Book.destory invoke
Book.myPreDestory invoke
---------------destroy-----------------

Spring Bean有三种配置方式:

传统的XML配置方式
基于注解的配置
基于类的Java Config

<bean id="beanFactroy" class="com.stonegeek.service.impl.BeanFactroyImpl" />

如果一个类使用了@Service,那么此类将自动注册成一个bean,不需要再在applicationContext.xml文件定义bean了,类似的还包括@Component、@Repository、@Controller。然后需要在applicationContext.xml文件中加一行,作用是自动扫描base-package包下的注解:

<context:component-scan base-package="com.stonegeek" />
@Service

通过java类定义spring配置元数据,且直接消除xml配置文件
Spring3.0基于java的配置直接支持下面的注解:
 @Configuration @Bean@DependsOn@Primary @Lazy@Import
 @ImportResource @Value

public class BeanFactoryImpl implements BeanFactory {
    @Override
    public void Beantest() {
    }
}
@Configuration
public class BeanConfig {
    @Bean
    public BeanFactory beanFactory(){
        return new BeanFactoryImpl();
    }
}

测试

public class TestBean2 {
    @Test
    public void test(){
        ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanFactory beanFactory=(BeanFactory) ctx.getBean("beanFactory");
        beanFactory.Beantest();  //This is a 基于java注解的bean!
    }
}

借鉴:https://www.cnblogs.com/javazhiyin/p/10905294.html
https://cloud.tencent.com/developer/article/1516796

发布了29 篇原创文章 · 获赞 0 · 访问量 1640

猜你喜欢

转载自blog.csdn.net/glamour2015/article/details/104449796