spring bean创建流程+demo

Bean创建流程:

spring的一大优点就是扩展性很强,比如,在spring bean 的生命周期中,给我们预留了很多参与bean 的生命周期的方法。

spring bean创建流程+demo_第1张图片

大致梳理一下,有以下几种:

  1. 自定义 org.springframework.beans.factory.config.BeanPostProcessor ,来让 spring 回调我们的方法来参与 bean的生命周期。
  2. 在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用;
  3. 通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;
  4. 通过 元素的 init-method/destroy-method属性指定初始化之后 /销毁之前调用的操作方法;

具体流程如下:

  1. 实例化:利用构造方法来实例化得到一个对象(但是如何一个类中有多个构造方法,Spring则会进行选择,这个叫做推断构造方法);
  2. 依赖注入:实例化后,Spring会判断该对象中是否存在被@Autowired注解了的属性,把这些属性找出来并由Spring进行依赖注入;
  3. Aware回调:如果实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware等接口,则执行相应的重写方法;
  4. 执行BeanPostProcessor.postProcessBeforeInitialization()进行初始化前操作;
  5. 执行@PostConstruct注解对应的方法进行初始化;
  6. 执行重写的InitializingBean接口的afterPropertiesSet()方法进行初始化;
  7. 执行BeanPostProcessor.postProcessAfterInitialization()进行初始化后操作(Spring的AOP在此方法内实现);
    如果不用进行AOP,那么该Bean就是此类的构造方法所得到的对象。
    如果需要进行AOP,那么该Bean就是通过动态代理生成一个代理对象,而不是该类本身所得到的对象。
  8. 执行@PreDestroy注解对应的方法进行销毁前操作;
  9. 执行重写的DisposableBean接口的destroy()方法进行销毁操作;

/**
 * @author Herbert
 */
@Component
public class DemoController implements InitializingBean,DisposableBean {

    @Autowired
    private DemoService demoService;
    private String name = "Herbert";

    public DemoController() {
        System.out.println();
        System.out.println("constructor ");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }

    @PostConstruct
    public void  postConstruct(){
        System.out.println();
        System.out.println("@PostConstrut");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println();
        System.out.println("afterPropertiesSet");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }

    @PreDestroy
    public void  preDestroy(){
        System.out.println();
        System.out.println("@PreDestroy");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }
    @Override
    public void destroy() throws Exception {
        System.out.println();
        System.out.println("destroy");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }
    public void init(){
        System.out.println();
        System.out.println("init-method by xml 配置文件");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }
    public void  cleanUp(){
        System.out.println();
        System.out.println("destroy-method by xml 配置文件");
        System.out.println( "name:" + name);
        System.out.println( "demoService:" + demoService);
        System.out.println();
    }
}

/**
 * @author Herbert
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DemoController){
            System.out.println();
            System.out.println("BeanPostProcessor:" + "postProcessBeforeInitialization");
            Field field = null;
            try {
                field = bean.getClass().getDeclaredField("demoService");
                field.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            try {
                Object o = field.get(bean);
                System.out.println( "demoService已注入:" + o);
                System.out.println();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DemoController){
            System.out.println();
            System.out.println("BeanPostProcessor:" + "postProcessAfterInitialization");
            Field field = null;
            try {
                field = bean.getClass().getDeclaredField("demoService");
                field.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            try {
                Object o = field.get(bean);
                System.out.println( "demoService已注入:" + o);
                System.out.println();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return bean;
    }
}
/**
 * @author Herbert
 */
@Component
public class DemoService {

}
/**
 * @author Herbert
 */
@SpringBootApplication
public class SpringBeanTest  {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringBeanTest.class, args);
        applicationContext.close();
    }

}

执行结果:
spring bean创建流程+demo_第2张图片

代码下载地址:springbeanDomo.rar

推断构造方法:

  1. 如果只有一个构造方法,用这个构造方法;
  2. 如果存在多个构造方法,用无参的构造方法,若不存在无参的构造方法,那么Spring就会报错;
  3. 如果某个构造方法上加了@Autowired注解,Spring就会用这个加了@Autowired注解的构造方法;

需要重视的是,如果Spring选择了一个有参的构造方法,Spring在调用这个有参构造方法时,需要传入参数,那这个参数是怎么来的呢?

Spring会根据入参的类型和入参的名字去Spring中找Bean对象(以单例Bean为例,Spring会从单例池那个Map中去找):

  1. 先根据入参类型找,如果只找到一个,那就直接用来作为入参;
  2. 如果根据类型找到多个,则再根据入参名字来确定唯一一个;
  3. 最终如果没有找到,则会报错,无法创建当前Bean对象。

AOP的大致流程(cglib):

  1. 生成代理类UserServiceProxy,代理类继承UserService;
  2. 代理类中重写了父类的方法,比如UserService中的test()方法;
  3. 代理类中还会有一个target属性,该属性的值为被代理对象(也就是通过UserService类推断构造方法实例化出来的对象,进行了依赖注入、初始化等步骤的对象)
  4. 当我们从Spring容器得到UserService的Bean对象时,拿到的就是UserServiceProxy所生成的对象,也就是代理对象。

代码下载地址:springbeanDomo.rar

你可能感兴趣的:(SpringBoot,java,spring,java)