• Spring注解开发(二)生命周期


    一,通过@Bean注解指定初始化和销毁方法

    <bean id="person" class="com.practice.bean.Person" init-method="" destroy-method=""  >

    和在XML配置文件中的格式一样,在@Bean注解中也有这两个属性

    String initMethod() default "";
    String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;

    在Person类中新建init和destroy方法

       private void init() {
            System.out.println("----->执行init方法");
        }
    
        private void destroy() {
            System.out.println("----->执行destroy方法");
        }

    配置类为:

    @Configuration
    @ComponentScan(value = "com.practice")
    public class MainConfig {
        @Bean(initMethod = "init",destroyMethod = "destroy")
        public Person person() {
            return new Person("Alen", 21);
        }
    }

    执行测试类:

     @Test
        public void test01() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
            Person bean = applicationContext.getBean(Person.class);
            System.out.println(bean.toString());
            applicationContext.close();
        }

    打印结果如下:

    ----->执行init方法
    Person{name='Alen', age=21}
    ----->执行destroy方法

    可以看出在容器创建的时候执行了init的方法(可以将getBean(Person.class)注释掉),在容器销毁时执行了destroy方法。

    以上是在该对象为单例的情况下,那么在多例的情况下又是如何呢?

    //为配置类中加载的组件加上如下注释
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

    可以看出,在容器创建的时候并没有执行初始化方法,是在获取该组件的时候执行init方法。而在容器关闭时也不会执行destroy方法。

    二,通过实现InitializingBean(定义初始化逻辑)

                          DisposableBean(定义销毁逻辑)

    让Person类实现这两个接口,可以看到需要实现两个方法:

      @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("--->执行afterPropertiesSet方法");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("--->执行destroy方法");
        }

    执行测试类,结果如下:

    --->执行afterPropertiesSet方法
    Person{name='Alen', age=21}
    --->执行destroy方法

    多例情况下也和第一部分中的情况一致。

    三,可以使用JSR250:

    @PostConstruct和@PreDestroy注解

    在Person类中,实现如下:

      @PostConstruct
        private void init() {
            System.out.println("----->执行init方法");
        }
    
        @PreDestroy
        private void destroy() {
            System.out.println("----->执行destroy方法");
        }

    执行测试类,结果如下:

    ----->执行init方法
    Person{name='Alen', age=21}
    ----->执行destroy方法

    多例情况下也和第一部分中的情况一致。

    四,实现BeanPostProcessor(Bean的后置处理器)

    Spring还提供了BeanPostProcessor接口在执行初始化前和初始化后的处理器,在该接口中定义了以下两个方法:

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

    Person实现该接口,重写这两个方法。

    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("--->执行postProcessBeforeInitialization方法"+beanName);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("--->执行postProcessAfterInitialization方法"+beanName);
            return bean;
        }
    }

    执行测试类,结果如下:

    --->执行postProcessBeforeInitialization方法mainConfig
    --->执行postProcessAfterInitialization方法mainConfig
    --->执行postProcessBeforeInitialization方法person
    ----->执行init方法
    --->执行postProcessAfterInitialization方法person
    Person{name='Alen', age=21}
    ----->执行destroy方法

    可以看出在执行init方法前后,组件person分别调用了postProcessBeforeInitialization方法和postProcessAfterInitialization方法。

    那么它是怎么工作的呢,我们在postProcessBeforeInitialization的返回值前加上断点,debug启动测试类:

    从容器创建开始进入,找到postProcessBeforeInitialization方法怎么执行的(按照debug路径):

    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
           //创建一个新的AnnotationConfigApplicationContext,需要进行属性赋值
           //tip:此处逻辑后序阅读源码时再学习		
            this();
           //注册传入的配置类
    	  register(annotatedClasses);
           //将传入的资源持久化
    	  refresh();
    	}

    进入refresh方法:可以看到调用了finishBeanFactoryInitialization方法--->实例化所有剩下的(非延迟加载)单例。

    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);

    再进入DefaultListableBeanFactory的preInstantiateSingletons方法,按照debug路径,

    最终到达AbstractAutowireCapableBeanFactory类的doCreateBean方法,在该方法中有如下代码:

    try {
       populateBean(beanName, mbd, instanceWrapper);
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    • populateBean():使用Bean定义中的属性值填充给定BeanWrapper中的Bean实例。

    在initializeBean方法中,我们终于看到了解析BeanPostProcessor的方法

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
    //执行postProcessBeforeInitialization方法
    	wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    	}
    
    try {
    //执行初始化方法
    	invokeInitMethods(beanName, wrappedBean, mbd);
    	}
    catch (Throwable ex) {
    		throw new BeanCreationException(
    		(mbd != null ? mbd.getResourceDescription() : null),
    		beanName, "Invocation of init method failed", ex);
    	}
    if (mbd == null || !mbd.isSynthetic()) {
    //执行postProcessAfterInitialization方法
    	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    	}
    
    return wrappedBean;

    一。先来看一下applyBeanPostProcessorsBeforeInitialization方法

    @Override
    	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor processor : getBeanPostProcessors()) {
    			Object current = processor.postProcessBeforeInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}

    通过getBeanPostProcessors()方法,获取到所有的BeanPostProcesors列表

    0 = {ApplicationContextAwareProcessor@1856} 
    1 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@1857} 
    2 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@1858} 
    3 = {MyBeanPostProcessor@1787} 
    4 = {CommonAnnotationBeanPostProcessor@1768} 
    5 = {AutowiredAnnotationBeanPostProcessor@1757} 
    6 = {ApplicationListenerDetector@1859} 

    并遍历执行,其中有自定义的MyBeanPostProcessor类,此处将会执行我们重写的postProcessBeforeInitialization方法。在列表中还有InitDestroyAnnotationBeanPostProcessor组件,该组件的作用就是找到容器中加了initAnnotationType注解(或destroyAnnotationType)的方法,并通过反射去调用它,@PostConstruct就属于initAnnotationType注解,所以在此处就会执行Person的init方法。

    二。再看一下postProcessAfterInitialization方法,流程也是一样

    @Override
    	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor processor : getBeanPostProcessors()) {
    			Object current = processor.postProcessAfterInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}

    getBeanPostProcessors方法获取用于创建该组件的BeanPostProcessors 列表,遍历并执行postProcessAfterInitialization方法,如果返回的为空则直接返回包装好的该实例。

    三。在invokeInitMethods方法中做了什么。

    在invokeInitMethods主要有以下两个方法:

    ((InitializingBean) bean).afterPropertiesSet();
    invokeCustomInitMethod(beanName, bean, mbd);

    1.在该类中先判断了当前组件是否为InitializingBean:bean instanceof InitializingBean。然后执行

    ((InitializingBean) bean).afterPropertiesSet()方法(在属性赋值完成和BeanPostProcessorsBeforeInitialization方法后)。

    2.invokeCustomInitMethod(beanName, bean, mbd)执行客户自定义的初始化方法,此处从RootBeanDefinition获取到initMethodName(此处可以发现@Bean(initMethod = "init",destroyMethod = "destroy")该注解中的init方法)并通过反射调用该方法,执行init方法。

    四。BeanPostProcessor在Spring底层的应用

    中,可以看到applyBeanPostProcessorsBeforeInitialization在获取所有的BeanPostProcesors列表,在列表中还有其他几BeanPostProcessor。

    以ApplicationContextAwareProcessor为例,在其方法中为实现ApplicationContextAware接口的组件注入了ApplicationContext;ApplicationContextAwareProcessor源码中可以看出:

    先执行实现的postProcessBeforeInitialization,先进行安全验证相关,然后执行了invokeAwareInterfaces(bean)方法:

    private void invokeAwareInterfaces(Object bean) {
    		if (bean instanceof Aware) {
    			if (bean instanceof EnvironmentAware) {
    				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    			}
    			if (bean instanceof EmbeddedValueResolverAware) {
    				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    			}
    			if (bean instanceof ResourceLoaderAware) {
    				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    			}
    			if (bean instanceof ApplicationEventPublisherAware) {
    				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    			}
    			if (bean instanceof MessageSourceAware) {
    				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    			}
    			if (bean instanceof ApplicationContextAware) {
    				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    			}
    		}
    	}

    为实现类传入了ApplicationContext。

  • 相关阅读:
    CPU使用率100%的一个原因
    Oracle 9.2.0.1升级到9.2.0.5
    Javacript同样的意思,更巧的写法
    前端面试题
    Linux shell
    vi/vim 光标移动命令
    CSS 中的分离、抽象和层叠
    practice first开张
    Linux下访问Windows的方法(原)
    Evolution收发Gmail邮件
  • 原文地址:https://www.cnblogs.com/demo-alen/p/13547232.html
Copyright © 2020-2023  润新知