Spring5注解驱动(四)

3.生命周期


3.1. @Bean指定初始化和销毁方法

首先,定义一个Car类:

package com.hutu.bean;

public class Car {

    public Car() {
        System.out.println("car constructor...");
    }

    public void init() {
        System.out.println("car ... init ...");
    }

    public void destroy() {
        System.out.println("car ... destroy ...");
    }

}

配置类:MainConfigOfLifeCycle

package com.hutu.config;

import com.hutu.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * bean的生命周期:bean的创建->初始化->销毁的过程
 * 容器管理bean的生命周期:
 * 可以自定义初始化方法和销毁的方法:容器在bean进行到当前的生命周期的时候,来调用我们自定义的初始化方法和销毁方法
 * 
 * 构造(对象创建):
 *   -- 单实例:在容器启动的时候创建对象
 *   -- 多实例:在每次获取的时候来创建对象
 * 初始化方法:
 *   --  对象创建完成,并赋值好,调用初始化方法
 * 销毁方法:
 *   -- 单实例的bean:在容器关闭的时候进行销毁
 *   -- 多实例的bean:容器不会管理这个bean,容器不会调用销毁的方法
 * <p>
 * 1)指定初始化方法和销毁方法;
 * 可以通过@Bean(initMethod = "init",destroyMethod = "destroy")来指定初始化方法和销毁方法
 * 相当于xml配置文件bean标签里面的 init-method="" 和 destroy-method="" 属性
 */
@Configuration
public class MainConfigOfLifeCycle {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

测试

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
}

此时,还没有关闭IOC容器的时候,运行结果为

car constructor...
car ... init ...
容器创建完成

而当调用了容器的close方法关闭容器的时候:

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    context.close();
}

测试的运行结果为:

car constructor...
car ... init ...
容器创建完成
car ... destroy ...

而当bean的作用域为多例的时候:

@Configuration
public class MainConfigOfLifeCycle {

    @Scope("prototype")
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

再次测试

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    context.close();
}

测试结果

容器创建完成

当bean的作用域为多例的时候,只有在获取的时候,才会创建对象,而且在IOC容器关闭的时候,是不进行销毁的 :

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    Object car = context.getBean("car");
    context.close();
}

测试结果

容器创建完成
car constructor...
car ... init ...

3.2. InitializingBeanDisposableBean

InitializingBean接口:在bean的初始化方法调用之后进行调用

package org.springframework.beans.factory;


public interface InitializingBean {

	/**
	 * Invoked by the containing {@code BeanFactory} after it has set all bean properties
	 * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
	 * <p>This method allows the bean instance to perform validation of its overall
	 * configuration and final initialization when all bean properties have been set.
	 * @throws Exception in the event of misconfiguration (such as failure to set an
	 * essential property) or if initialization fails for any other reason
	 */
	void afterPropertiesSet() throws Exception;

}

DisposableBean 接口

package org.springframework.beans.factory;

public interface DisposableBean {

	/**
	 * Invoked by the containing {@code BeanFactory} on destruction of a bean.
	 * @throws Exception in case of shutdown errors. Exceptions will get logged
	 * but not rethrown to allow other beans to release their resources as well.
	 */
	void destroy() throws Exception;

}

cat类:实现这两个接口

package com.hutu.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Car implements InitializingBean, DisposableBean {

    public Car() {
        System.out.println("car constructor...");
    }

    public void init() {
        System.out.println("car ... init ...");
    }

    @Override
    public void destroy() {
        System.out.println("car ... destroy ...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Cat...afterPropertiesSet...");
    }
}

用包扫描的方式来进行装配

@Configuration
@ComponentScan("com.hutu.bean")
public class MainConfigOfLifeCycle {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

测试

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    context.close();
}

测试结果

car constructor...
Cat...afterPropertiesSet...
car ... init ...
容器创建完成
car ... destroy ...

3.3. @PostConstruct&@PreDestroy

可以使用JSR250规范里面定义的两个注解:

  • @PostConstruct :在bean创建完成并且属性赋值完成,来执行初始化方法

  • @PreDestroy :在容器销毁bean之前通知我们来进行清理工作


@PostConstruct:在bean创建完成并且属性赋值完成,来执行初始化方法

@PreDestroy:在容器销毁bean之前通知我们来进行清理工作

定义一个Dog类

package com.hutu.bean;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class Dog {
    public Dog() {
        System.out.println("Dog...Contructor...");
    }

    //在对象创建并赋值之后调用
    @PostConstruct
    public void init() {
        System.out.println("Dog...@PostConstruct...");
    }

    //在对象创建并赋值之后调用
    @PreDestroy
    public void destroy() {
        System.out.println("Dog...@PreDestroy...");
    }
}

再来运行这个测试方法:

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    context.close();
}

测试结果

Dog...Contructor...
Dog...@PostConstruct...
car constructor...
Cat...afterPropertiesSet...
car ... init ...
容器创建完成
car ... destroy ...
Dog...@PreDestroy...

3.4. BeanPostProcessor-后置处理器

BeanPostProcessor接口:bean的后置处理器,在bean初始化前后做一些处理工作,这个接口有两个方法:

  • postProcessBeforeInitialization:在初始化之前工作

  • postProcessAfterInitialization:在初始化之后工作


BeanPostProcessor接口

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;

public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

同样,还是使用包扫描的方式来进行装配:

@Configuration
@ComponentScan("com.hutu.bean")
@ComponentScan("com.hutu.config")
public class MainConfigOfLifeCycle {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

写一个类并且实现这个后置处理器接口 BeanPostProcessor :

package com.hutu.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
        return bean;
    }
}

测试

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    context.close();
}

测试结果

通过自定义的匹配规则--->com.hutu.test.MainTest
通过自定义的匹配规则--->com.hutu.test.MainTest01
通过自定义的匹配规则--->com.hutu.bean.Blue
通过自定义的匹配规则--->com.hutu.bean.Car
通过自定义的匹配规则--->com.hutu.bean.Color
通过自定义的匹配规则--->com.hutu.bean.Dog
通过自定义的匹配规则--->com.hutu.bean.Person
通过自定义的匹配规则--->com.hutu.bean.RainBow
通过自定义的匹配规则--->com.hutu.bean.Red
通过自定义的匹配规则--->com.hutu.bean.Yellow
通过自定义的匹配规则--->com.hutu.config.ColorFactoryBean
通过自定义的匹配规则--->com.hutu.config.LinuxCondition
通过自定义的匹配规则--->com.hutu.config.MainConfig2
通过自定义的匹配规则--->com.hutu.config.MainConfigOfLifeCycle
通过自定义的匹配规则--->com.hutu.config.MyBeanPostProcessor
通过自定义的匹配规则--->com.hutu.config.MyImportBeanDefinitionRegistrar
通过自定义的匹配规则--->com.hutu.config.MyImportSelector
通过自定义的匹配规则--->com.hutu.config.MyTypeFilter
通过自定义的匹配规则--->com.hutu.config.WindowsCondition
通过自定义的匹配规则--->com.hutu.controller.BookController
通过自定义的匹配规则--->com.hutu.dao.BookDao
通过自定义的匹配规则--->com.hutu.service.BookService
postProcessBeforeInitialization...mainConfigOfLifeCycle=>com.hutu.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$58dbf743@50a638b5
postProcessAfterInitialization...mainConfigOfLifeCycle=>com.hutu.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$58dbf743@50a638b5
Dog...Contructor...
postProcessBeforeInitialization...dog=>com.hutu.bean.Dog@1725dc0f
Dog...@PostConstruct...
postProcessAfterInitialization...dog=>com.hutu.bean.Dog@1725dc0f
postProcessBeforeInitialization...mainConfig=>com.hutu.config.MainConfig$$EnhancerBySpringCGLIB$$d6ed4678@3911c2a7
postProcessAfterInitialization...mainConfig=>com.hutu.config.MainConfig$$EnhancerBySpringCGLIB$$d6ed4678@3911c2a7
postProcessBeforeInitialization...mainConfig2=>com.hutu.config.MainConfig2$$EnhancerBySpringCGLIB$$5b037c42@4ac3c60d
postProcessAfterInitialization...mainConfig2=>com.hutu.config.MainConfig2$$EnhancerBySpringCGLIB$$5b037c42@4ac3c60d
postProcessBeforeInitialization...person=>Person(name=null, age=null)
postProcessAfterInitialization...person=>Person(name=null, age=null)
postProcessBeforeInitialization...myTypeFilter=>com.hutu.config.MyTypeFilter@76508ed1
postProcessAfterInitialization...myTypeFilter=>com.hutu.config.MyTypeFilter@76508ed1
postProcessBeforeInitialization...bookController=>com.hutu.controller.BookController@41e36e46
postProcessAfterInitialization...bookController=>com.hutu.controller.BookController@41e36e46
postProcessBeforeInitialization...bookService=>com.hutu.service.BookService@15c43bd9
postProcessAfterInitialization...bookService=>com.hutu.service.BookService@15c43bd9
postProcessBeforeInitialization...person666=>Person(name=小糊涂仙, age=20)
postProcessAfterInitialization...person666=>Person(name=小糊涂仙, age=20)
postProcessBeforeInitialization...com.hutu.bean.Color=>com.hutu.bean.Color@188715b5
postProcessAfterInitialization...com.hutu.bean.Color=>com.hutu.bean.Color@188715b5
postProcessBeforeInitialization...com.hutu.bean.Red=>com.hutu.bean.Red@1ea9f6af
postProcessAfterInitialization...com.hutu.bean.Red=>com.hutu.bean.Red@1ea9f6af
postProcessBeforeInitialization...com.hutu.bean.Blue=>com.hutu.bean.Blue@6a192cfe
postProcessAfterInitialization...com.hutu.bean.Blue=>com.hutu.bean.Blue@6a192cfe
postProcessBeforeInitialization...com.hutu.bean.Yellow=>com.hutu.bean.Yellow@5119fb47
postProcessAfterInitialization...com.hutu.bean.Yellow=>com.hutu.bean.Yellow@5119fb47
postProcessBeforeInitialization...bill=>Person(name=Bill Gates, age=28)
postProcessAfterInitialization...bill=>Person(name=Bill Gates, age=28)
postProcessBeforeInitialization...linux=>Person(name=linus, age=19)
postProcessAfterInitialization...linux=>Person(name=linus, age=19)
postProcessBeforeInitialization...colorFactoryBean=>com.hutu.config.ColorFactoryBean@1dde4cb2
postProcessAfterInitialization...colorFactoryBean=>com.hutu.config.ColorFactoryBean@1dde4cb2
postProcessBeforeInitialization...rainBow=>com.hutu.bean.RainBow@393671df
postProcessAfterInitialization...rainBow=>com.hutu.bean.RainBow@393671df
car constructor...
postProcessBeforeInitialization...car=>com.hutu.bean.Car@55b7a4e0
Cat...afterPropertiesSet...
car ... init ...
postProcessAfterInitialization...car=>com.hutu.bean.Car@55b7a4e0
容器创建完成
car ... destroy ...
Dog...@PreDestroy...

3.5. BeanPostProcessor原理

在这个后置处理器的两个方法上面打上断点

以debug的方式来运行这个测试方法

前置处理器调用的方法:

调用getBeanPostProcessors()方法找到容器里面的所有的BeanPostProcessor,挨个遍历,调用BeanPostProcessor的postProcessBeforeInitialization方法,一旦调用postProcessBeforeInitialization方法的返回值为null的时候,就直接跳出遍历 ,后面的BeanPostProcessor 的postProcessBeforeInitialization也就不会执行了:

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)  throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

后置处理器调用的方法:

调用getBeanPostProcessors()方法找到容器里面的所有的BeanPostProcessor,挨个遍历,调用BeanPostProcessor的postProcessAfterInitialization方法,一旦调用postProcessAfterInitialization方法的返回值为null的时候,就直接跳出遍历 ,后面的BeanPostProcessor 的postProcessAfterInitialization也就不会执行了:

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

//前置处理器执行 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //初始化方法执行 invokeInitMethods(beanName, wrappedBean, mbd); //后置处理器执行 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

在看源码的时候,可以发现: 在执行exposedObject = initializeBean(beanName, exposedObject, mbd);方法之前先调用了populateBean(beanName, mbd, instanceWrapper);这个方法:

populateBean(beanName, mbd, instanceWrapper);–给bean进行属性赋值 exposedObject = initializeBean(beanName, exposedObject, mbd);–初始化方法,在这个初始化方法内部包括了前置处理器、初始化方法、后置处理器的调用

3.6. BeanPostProcessor在Spring底层的使用

Spring底层对 BeanPostProcessor 的使用:

  • bean赋值,注入其他组件,@Autowired,生命周期注解等功能,@Async等等都是使用BeanPostProcessor来完成的


BeanPostProcessor 这个接口有很多的实现类

如果我们想要获取IOC容器,可以这样做:

package com.hutu.bean;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class Dog implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Dog() {
        System.out.println("Dog...Contructor...");
    }

    //在对象创建并赋值之后调用
    @PostConstruct
    public void init() {
        System.out.println("Dog...@PostConstruct...");
    }

    //在对象创建并赋值之后调用
    @PreDestroy
    public void destroy() {
        System.out.println("Dog...@PreDestroy...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

可以debug来调试

还可以debug运行这个测试方法

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成");
    context.close();
}

实际上BeanPostProcessor接口还有很多的实现类,比如说BeanValidationPostProcessor,这个是用来做数据校验的:

像InitDestroyAnnotationBeanPostProcessor这个实现类就是实现了@PostConstruct和@PreDestroy这两个注解的功能:

在这个地方打个断点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值