百味皆苦 java后端开发攻城狮

spring注解驱动开发(生命周期)

2019-05-13
百味皆苦

使用@Bean指定初始化和销毁方法

  • 使用@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...");
    }

}

/**
 * bean的生命周期:bean的创建->初始化->销毁的过程
 * 容器管理bean的生命周期:
 * 我们可以自定义初始化方法和销毁的方法:容器在bean进行到当前的生命周期的时候,来调用我们自定义的初始化方法和销毁方法
 * 构造(对象创建):
 *      单实例:在容器启动的时候创建对象
 *      多实例:在每次获取的时候来创建对象
 * 初始化方法:
 *      对象创建完成,并赋值好,调用初始化方法
 * 销毁方法:
 *      单实例的bean:在容器关闭的时候进行销毁
 *      多实例的bean:容器不会管理这个bean,容器不会调用销毁的方法
 *
 * 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() {
        //1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成");
        applicationContext.close();
    }

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

多实例

@Configuration
public class MainConfigOfLifeCycle {

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

容器创建完成

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

InitializingBean接口

  • InitializingBean接口:在BeanFactory设置完bean的属性值之后进行调用,相当于初始化方法
public interface InitializingBean {

	/**
	 * Invoked by a BeanFactory after it has set all bean properties supplied
	 * (and satisfied BeanFactoryAware and ApplicationContextAware).
	 * <p>This method allows the bean instance to perform initialization only
	 * possible when all bean properties have been set and to throw an
	 * exception in the event of misconfiguration.
	 * @throws Exception in the event of misconfiguration (such
	 * as failure to set an essential property) or if initialization fails.
	 */
	void afterPropertiesSet() throws Exception;

}

DisposableBean接口

  • DisposableBean接口:由bean工厂在销毁单例时调用
public interface DisposableBean {

	/**
	 * Invoked by a BeanFactory on destruction of a singleton.
	 * @throws Exception in case of shutdown errors.
	 * Exceptions will get logged but not rethrown to allow
	 * other beans to release their resources too.
	 */
	void destroy() throws Exception;

}

使用

@Component
public class Cat implements InitializingBean, DisposableBean {
    public Cat() {
        System.out.println("Cat...Contrustor...");
    }

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

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

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

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

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

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

@PostConstruct

@PreDestroy

  • 可以使用JSR250规范里面定义的两个注解:
  • @PostConstruct :在bean创建完成并且属性赋值完成,来执行初始化方法
  • @PreDestroy :在容器销毁bean之前通知我们来进行清理工作
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}

在项目的启动过程中或者项目启动成功后初始化一些资源、或者执行一些骚操作”,可能第一时间会想到“@PostConstruct”注解,确实,这个注解可以实现项目在启动过程中执行一些操作或者初始化一些资源,但是请记住,这个注解所注解的方法的业务逻辑是在“项目的启动过程中”阶段执行的,而不是“项目启动成功后”阶段。

//简单的打印一句话
@Service
public class InitRunnerService {
    private static final Logger log= LoggerFactory.getLogger(InitRunnerService.class);

    @PostConstruct
    public void init(){
        log.info("--@PostConstruct方式-SpringBoot容器启动之后执行一些初始化的内容....--");

    }
}

运行项目,观察项目的运行情况,会发现,“@PostConstruct”注解所注解的方法的逻辑在项目的启动过程的某个阶段成功执行了。

我们想要的在“项目启动成功后”的阶段执行一些我们制定的方法逻辑或者初始化一些资源,而不是在项目的启动过程!之所以不是在“项目的启动过程”阶段执行,是因为万一该注解所注解的方法的业务逻辑执行起来时间很长或者在执行的过程出现了一些令人意想不到的异常,那么很有可能会因此而影响整个项目的启动过程,甚至会出现“项目启动失败”的现象!

使用

@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() {
        //1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成");
        applicationContext.close();
    }

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

CommandLineRunner接口

基于“CommandLineRunner”接口实现项目在启动成功之后执行一些骚操作、初始化一些资源的功能!如果需要在项目启动成功之后做许多初始化操作,那么可以分成多个“实现CommandLineRunner接口”的实现类去执行,同时采用@Order(num)注解标注该实现类,num数值越小,就越先执行

// spring boot项目启动之后执行一些初始化的内容1
@Component
@Order(1)
public class InitRunnerOne implements CommandLineRunner{

    private static final Logger log= LoggerFactory.getLogger(InitRunnerOne.class);

    @Autowired
    private SysConfigMapper sysConfigMapper;

    //TODO:SpringBoot容器启动之后执行一些初始化的内容:比如将一些频繁访问的数据字典塞至缓存中....
    @Override
    public void run(String... strings) throws Exception {
        log.info("--1~SpringBoot容器启动之后执行一些初始化的内容....--");

        SysConfig sysConfig=sysConfigMapper.selectByPrimaryKey(5);
        log.info("--项目启动成功后初始化资源:{}",sysConfig);
    }
}

第二个

@Component
@Order(2)
public class InitRunnerTwo implements CommandLineRunner{

    private static final Logger log= LoggerFactory.getLogger(InitRunnerTwo.class);

    //TODO:SpringBoot容器启动之后执行一些初始化的内容....
    @Override
    public void run(String... strings) throws Exception {
        log.info("--2~SpringBoot容器启动之后执行一些初始化的内容....--");

    }
}

将项目启动起来,观察控制台的输出,会发现最终的输出结果如我们所愿!

BeanPostProcessor接口

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

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * <p>This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other BeanPostProcessor callbacks.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

使用

@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() {
        //1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成");
        applicationContext.close();
    }

postProcessBeforeInitialization…org.springframework.context.event.internalEventListenerProcessor=>org.springframework.context.event.EventListenerMethodProcessor@36f0f1be
postProcessAfterInitialization…org.springframework.context.event.internalEventListenerProcessor=>org.springframework.context.event.EventListenerMethodProcessor@36f0f1be

postProcessBeforeInitialization…org.springframework.context.event.internalEventListenerFactory=>org.springframework.context.event.DefaultEventListenerFactory@6ee12bac
postProcessAfterInitialization…org.springframework.context.event.internalEventListenerFactory=>org.springframework.context.event.DefaultEventListenerFactory@6ee12bac

postProcessBeforeInitialization…mainConfigOfLifeCycle=>com.ldc.config.MainConfigOfLifeCycleEnhancerBySpringCGLIBEnhancerBySpringCGLIB27d6c7d3@64c87930
postProcessAfterInitialization…mainConfigOfLifeCycle=>com.ldc.config.MainConfigOfLifeCycleEnhancerBySpringCGLIBEnhancerBySpringCGLIB27d6c7d3@64c87930

Cat…Contrustor…
postProcessBeforeInitialization…cat=>com.ldc.bean.Cat@525f1e4e
Cat…afterPropertiesSet…
postProcessAfterInitialization…cat=>com.ldc.bean.Cat@525f1e4e

Dog…Contructor…
postProcessBeforeInitialization…dog=>com.ldc.bean.Dog@5ea434c8
Dog…@PostConstruct…
postProcessAfterInitialization…dog=>com.ldc.bean.Dog@5ea434c8

car constructor…
postProcessBeforeInitialization…car=>com.ldc.bean.Car@1d548a08
car…init…
postProcessAfterInitialization…car=>com.ldc.bean.Car@1d548a08

容器创建完成
car…destroy…
Dog…@PreDestroy…
Cat…destroy…

原理

  • 前置处理器调用的方法:调用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;
	}

底层

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

获取IOC容器

@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;
    }
}

数据校验

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

@Value

public class Person {

    //使用@Value赋值
    //1.基本的数值
    //2.可以写SpEL: #{}
    //3.可以写${}:取出配置文件中的值(在运行环境变量里面的值)
    @Value("张三")
    private String name;
    
    @Value("#{20-2}")
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

@Configuration
public class MainConfigOfPropertyValues {

    @Bean
    public Person person() {
        return new Person();
    }
}

    @Test
    public void test01() {
        //1.创建IOC容器
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        System.out.println("====================");

        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
        printBeans(applicationContext);
    }

    private void printBeans(ApplicationContext applicationContext) {
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : definitionNames) {
            System.out.println(name);
        }
    }

====================
Person{name=‘张三’, age=18}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfPropertyValues
person

@PropertySource

  • 使用@PropertySource注解加载外部配置文件
public class Person {

    //使用@Value赋值
    //1.基本的数值
    //2.可以写SpEL: #{}
    //3.可以写${}:取出配置文件【properties】中的值(在运行环境变量里面的值)
    @Value("张三")
    private String name;

    @Value("#{20-2}")
    private Integer age;

    private String nickName;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }


    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

  • 写上一个person.properties文件
person.nickName=小张三
  • 在xml文件中的配置是这样的
<context:property-placeholder location="classpath:person.properties"/>
  • 现在,我们用注解的方式就可以这样来做:
  • 我们要添加这样的一个注解:@PropertySource查看源码的时候,我们可以发现,这个注解是一个可重复标注的注解,可多次标注,也可以在一个注解内添加外部配置文件位置的数组,我们也可以用PropertySources内部包含多个PropertySource :
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {

	/**
	 * Indicate the name of this property source. If omitted, a name will
	 * be generated based on the description of the underlying resource.
	 * @see org.springframework.core.env.PropertySource#getName()
	 * @see org.springframework.core.io.Resource#getDescription()
	 */
	String name() default "";

	/**
	 * Indicate the resource location(s) of the properties file to be loaded.
	 * For example, {@code "classpath:/com/myco/app.properties"} or
	 * {@code "file:/path/to/file"}.
	 * <p>Resource location wildcards (e.g. *&#42;/*.properties) are not permitted;
	 * each location must evaluate to exactly one {@code .properties} resource.
	 * <p>${...} placeholders will be resolved against any/all property sources already
	 * registered with the {@code Environment}. See {@linkplain PropertySource above}
	 * for examples.
	 * <p>Each location will be added to the enclosing {@code Environment} as its own
	 * property source, and in the order declared.
	 */
	String[] value();

	/**
	 * Indicate if failure to find the a {@link #value() property resource} should be
	 * ignored.
	 * <p>{@code true} is appropriate if the properties file is completely optional.
	 * Default is {@code false}.
	 * @since 4.0
	 */
	boolean ignoreResourceNotFound() default false;

	/**
	 * A specific character encoding for the given resources, e.g. "UTF-8".
	 * @since 4.3
	 */
	String encoding() default "";

	/**
	 * Specify a custom {@link PropertySourceFactory}, if any.
	 * <p>By default, a default factory for standard resource files will be used.
	 * @since 4.3
	 * @see org.springframework.core.io.support.DefaultPropertySourceFactory
	 * @see org.springframework.core.io.support.ResourcePropertySource
	 */
	Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;

}

//@PropertySources :内部可以指定多个@PropertySource
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertySources {

	PropertySource[] value();

}

使用

//使用@PropertySource读取外部配置文件中的key/value保存到运行的环境变量中
//加载完外部配置文件以后使用${}取出配置文件的值
@PropertySource(value = {"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {

    @Bean
    public Person person() {
        return new Person();
    }
}

public class Person {

    //使用@Value赋值
    //1.基本的数值
    //2.可以写SpEL: #{}
    //3.可以写${}:取出配置文件【properties】中的值(在运行环境变量里面的值)
    @Value("张三")
    private String name;

    @Value("#{20-2}")
    private Integer age;

    @Value("${person.nickName}")
    private String nickName;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }


    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

====================
Person{name=‘张三’, age=18, nickName=‘小张三’}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfPropertyValues
person

环境变量

  • 我们还可以用Environment里面的getProperty()方法来获取:
@Test
    public void test01() {
        //1.创建IOC容器
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        System.out.println("====================");

        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);

        Environment environment = applicationContext.getEnvironment();
        String property = environment.getProperty("person.nickName");
        System.out.println(property);

        printBeans(applicationContext);
    }

    private void printBeans(ApplicationContext applicationContext) {
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : definitionNames) {
            System.out.println(name);
        }
    }

====================
Person{name=‘张三’, age=18, nickName=‘小张三’}
小张三
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfPropertyValues
person

指定各个bean加载顺序

bean类中各个方法的执行顺序:

1:Bean 容器 / BeanFactory 通过对象的构造器或工厂方法先实例化 Bean(构造方法);

2:设置对象属性(setter方法)

3:检查 xxxAware 相关接口,如果有就调用相应的 setxxx 方法把所需要的 xxx 传入到 Bean 中。

4:检查是否存在有关联的 BeanPostProcessors执行执行 postProcessBeforeInitialization() 方法进行前置处理

5:调用 @PostConstruct注解的方法

6:如果 Bean 实现了 InitializingBean 接口,执行 afterPropertiesSet() 方法。

7:检查是否配置了自定义的 init-method 属性,如果有就调用指定方法。

8:检查是否存在有关联的 BeanPostProcessors 执行 postProcessAfterInitialization() 方法进行后置处理

9:使用bean

10:当容器关闭时,调用@PreDestroy注解的方法

11:如果实现了 DisposableBean 接口,如果有就调用 destory() 方法。

12如果 Bean 配置文件中的定义包含 destroy-method 属性,执行指定的方法。

bean中各个方法执行顺序

指定bean加载顺序:

@Order目前用的比较多的有以下3点:

1:控制AOP的类的加载顺序,也就是被@Aspect标注的类

2:控制ApplicationListener实现类的加载顺序

3:控制CommandLineRunner实现类的加载顺序

@DependsOn注解可以用来控制bean的创建顺序,该注解用于声明当前bean依赖于另外一个bean。所依赖的bean会被容器确保在当前bean实例化之前被实例化。

@DependsOn的使用:

1:直接或者间接标注在带有@Component注解的类上面;

2:直接或者间接标注在带有@Bean注解的方法上面;

3:使用@DependsOn注解到类层面仅仅在使用 component-scanning 方式时才有效,如果带有@DependsOn注解的类通过XML方式使用,该注解会被忽略,<bean depends-on="..."/>这种方式会生效。

4:参数注入(@Autowired)或者

@Bean 
public BeanA beanA(BeanB Beanb){} 

也可以用来控制bean的创建顺序,原理等同于@DependsOn


Similar Posts

Comments