zoukankan      html  css  js  c++  java
  • SpringBoot注解---4.扩展原理

    一、Bean的生命周期管理

    1. bean的实例化:调用bean的构造方法,我们可以在bean的无参构造方法中执行相应的逻辑。
    2. bean的初始化:在初始化时,可以通过BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法进行拦截,执行自定义的逻辑;通过@PostConstruct注解、InitializingBean和init-method来指定bean初始化前后执行的方法,在该方法中咱们可以执行自定义的逻辑。
    3. bean的销毁:可以通过@PreDestroy注解、DisposableBean和destroy-method来指定bean在销毁前执行的方法,在该方法中咱们可以执行自定义的逻辑。

    1.通过@Bean指定init-method和destroy-method

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

    使用时机:

    1. 初始化方法:对象创建完成,如果对象中存在一些属性,并且这些属性也都赋好值之后,那么就会调用bean的初始化方法。
    2. 销毁的方法:可以对数据源的连接等信息进行关闭和清理。
      单实例 多实例
    初始化 对于单实例bean来说,在Spring容器创建完成后,Spring容器会自动调用bean的初始化方法 在每次获取bean对象的时候,调用bean的初始化方法
    销毁 在容器关闭的时候,会调用bean的销毁方法 Spring容器不会管理这个bean,也就不会自动调用这个bean的销毁方法了

    2.通过让bean实现InitializingBean和DisposableBean两个接口

    (1)初始化bean

    Spring为bean提供了两种初始化的方式,实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),或者在配置文件或@Bean注解中通过init-method来指定,两种方式可以同时使用。

    1. 实现InitializingBean接口是直接调用afterPropertiesSet()方法,与通过反射调用init-method指定的方法相比,效率相对来说要高点。但是init-method方式消除了对Spring的依赖。
    2. 如果调用afterPropertiesSet方法时出错,那么就不会调用init-method指定的方法了。

    (2)销毁bean

    1. 实现org.springframework.beans.factory.DisposableBean接口的bean在销毁前,Spring将会调用DisposableBean接口的destroy()方法。
    2. 使用destroy-method

     前者与Spring耦合高,使用类型强转.方法名(),效率高;后者耦合低,使用反射,效率相对来说较低。

    【 注意】多实例bean的生命周期不归Spring容器来管理,这里的DisposableBean接口中的方法是由Spring容器来调用的,所以如果一个多实例bean实现了DisposableBean接口是没有啥意义的,因为相应的方法根本不会被调用,当然了,在XML配置文件中指定了destroy方法,也是没有任何意义的。所以,在多实例bean情况下,Spring是不会自动调用bean的销毁方法的。

    package com.meimeixia.bean;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Cat implements InitializingBean, DisposableBean {
    	
    	public Cat() {
    		System.out.println("cat constructor...");
    	}
    
    	/**
    	 * 会在容器关闭的时候进行调用
    	 */
    	@Override
    	public void destroy() throws Exception {
    		// TODO Auto-generated method stub
    		System.out.println("cat destroy...");
    	}
    
    	/**
    	 * 会在bean创建完成,并且属性都赋好值以后进行调用
    	 */
    	@Override
    	public void afterPropertiesSet() throws Exception {
    		// TODO Auto-generated method stub
    		System.out.println("cat afterPropertiesSet...");
    	}
    
    }

    3.使用JSR-250规范里面定义的@PostConstruct和@PreDestroy两个注解

    @PostConstruct注解是Java中的注解,并不是Spring提供的注解。@PostConstruct和@PreDestroy是Java规范JSR-250引入的注解,定义了对象的创建和销毁工作,同一期规范中还有@Resource注解,Spring也支持了这些注解。

    package com.meimeixia.bean;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    import org.springframework.stereotype.Component;
    
    /**
     *
     * @author liayun
     *
     */
    @Component
    public class Dog {
    
    	public Dog() {
    		System.out.println("dog constructor...");
    	}
    	
    	// 在对象创建完成并且属性赋值完成之后调用
    	@PostConstruct
    	public void init() {
    		System.out.println("dog...@PostConstruct...");
    	}
    	
    	// 在容器销毁(移除)对象之前调用
    	@PreDestroy
    	public void destory() {
    		System.out.println("dog...@PreDestroy...");
    	}
    	
    }
     注解 源码 执行顺序
    @PostConstruct

    在bean创建完成并且属性赋值完成之后,来执行初始化方法。

    Constructor(构造方法)→@Autowired(依赖注入)→@PostConstruct(注释的方法)

    @PreDestroy

    在容器销毁bean之前通知我们进行清理工作。

    调用destroy()方法→@PreDestroy→destroy()方法→bean销毁 

    4.通过让bean实现BeanPostProcessor接口

    (1)BeanPostProcessor是什么?

    BeanPostProcessor是一个接口,其中有两个方法,Spring容器中的每一个bean对象初始化前后,都会执行BeanPostProcessor接口的实现类中的这两个方法。

     接口 调用时机
    postProcessBeforeInitialization 在bean实例化和属性设置之后,自定义初始化方法之前被调用
    postProcessAfterInitialization 在自定义初始化方法之后被调用
    package com.meimeixia.bean;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.core.Ordered;
    import org.springframework.stereotype.Component;
    
    /**
     * 后置处理器,在初始化前后进行处理工作
     * @author liayun
     *
     */
    @Component // 将后置处理器加入到容器中,这样的话,Spring就能让它工作了
    public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
    
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
    		return bean;
    	}
    
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
    		return bean;
    	}
    
    	@Override
    	public int getOrder() {
    		// TODO Auto-generated method stub
    		return 3;
    	}
    
    }

    当容器中存在多个BeanPostProcessor的实现类时,会按照它们在容器中注册的顺序执行。对于自定义的BeanPostProcessor实现类,还可以让其实现Ordered接口自定义排序。

    (2)作用

      后置处理器可用于bean对象初始化前后进行逻辑增强。Spring提供了BeanPostProcessor接口的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的动态代理等等。

    (3)原理

    在Spring中调用initializeBean()方法之前,还调用了populateBean()方法来为bean的属性赋值

    在applyBeanPostProcessorsBeforeInitialization()方法中,会遍历所有BeanPostProcessor对象,然后依次执行所有BeanPostProcessor对象的postProcessBeforeInitialization()方法,一旦BeanPostProcessor对象的postProcessBeforeInitialization()方法返回null以后,则后面的BeanPostProcessor对象便不再执行了,而是直接退出for循环。

    populateBean(beanName, mbd, instanceWrapper); // 给bean进行属性赋值
    initializeBean(beanName, exposedObject, mbd)
    {
    	applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    	invokeInitMethods(beanName, wrappedBean, mbd); // 执行自定义初始化
    	applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    

    (4)Spring底层对BeanPostProcessor的使用

    bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxxBeanProcessor等。

  • 相关阅读:
    Oracle-通过创建索引加快SQL执行效率
    Oracle-DG,MRP进程无法正常应用问题处理,重启大法好
    Oracle-DG,12c pdb创建测试
    Oracle-DG,疑问主库添加日志后,备库未操作主库日志比备库日志数量多,有什么影响?
    Oracle-DG疑问,什么情况下主库会发出一个会话连接备库
    Oracle-DG 主库将log_archive_dest_state_2远程归档线程参数设置为defer,为什么dg还是处于实时同步状态?
    Oracle-rm误删除数据文件,如何强制删除文件启动db
    Oracle-buffer cache过小导致SQL执行时间长
    win10下完全卸载-重装MySQL
    VSCode配置详细教程
  • 原文地址:https://www.cnblogs.com/nxf-rabbit75/p/14619893.html
Copyright © 2011-2022 走看看