spring源码分析(一):bean的加载和生命周期

版权声明:本文为博主原创文章,转载请注明出处!!!!!!!!!! https://blog.csdn.net/qq_21434959/article/details/83374488

1. 说明

现在开发大多数使用springboot 配置,自spring4.x后推荐使用@bean 注解式进行容器组件的注入 ,这篇文章简要对比了注解开发和xml开发,并介绍了在注解开发中bean的生命周期。

2. IOC容器创建对比

xml方式

bean.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd ">

    <context:property-placeholder location="classpath:person.properties"/>
    <!-- 包扫描、只要标注了@Controller、@Service、@Repository,@Component -->
    <!-- <context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan> -->
    <bean id="person" class="com.uu.anhusky.bean.Person" scope="prototype">
        <property name="age" value="1"/>
        <property name="name" value="zhangsan"/>
    </bean>

    <!-- 开启基于注解版的切面功能 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <!-- <tx:annotation-driven/> -->

</beans>
	@Test
    public void test01() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person.toString());
        printBeanName(applicationContext);
    }

注解bean方式

Config配置文件

@Configuration  // 告诉spring这是一个配置类
public class MainConfig {

    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean()
    public Person person() {
        return new Person("张三", 22);
    }
}
	@Test
    public void test01() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person.toString());
        printBeanName(applicationContext);

    }

3. 常用注解

3.1 加载bean的注解

 1 ). @Configuration 告诉spring这是一个配置类
 2 ). @ComponentScan	扫描包配置
		value: 扫描包的相对路径
		includeFilters: 过滤器配置,使用这个,要就将useDefaultFilters=false,手动操作
			@Filter :定义过滤规则
				   FilterType.ANNOTATION:按照注解
				   FilterType.ASSIGNABLE_TYPE:按照给定的类型;
				   FilterType.ASPECTJ:使用ASPECTJ表达式
				   FilterType.REGEX:使用正则指定
				   FilterType.CUSTOM:使用自定义规则
		excludeFilters :同上
3 ). @Bean 加载

配置类示例:

@Configuration  // 告诉spring这是一个配置类
@ComponentScan(value = "com.uu.anhusky",
        includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
               // @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}),
               // @ComponentScan.Filter(type= FilterType.CUSTOM,classes={MyTypeFilter.class})
        },
        useDefaultFilters = false
)

public class MainConfig {

    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean()
    public Person person() {
        return new Person("张三", 22);
    }
}

自定义Filter 示例:

public class MyTypeFilter implements TypeFilter {

    /**
     * @param metadataReader
     * @param metadataReaderFactory
     * @return
     * @throws IOException
     */
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // 获取当前类注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // 获取当前类路径信息
        Resource resource = metadataReader.getResource();
        // 获取当前类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();

        System.out.println("--->" + className);
        if (className.contains("er")) {
            return true;
        }
        return false;
    }
}
4 ). @Conditional【type】【method】按条件加载
	使用方式:
			定义实现Condition的类,配置bean

condition实现类如下:

// 根据系统判断是否加载bean
public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取系统名称
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("Linux")){
            return true;
        }
        return false;
    }
}

Configuration配置

@Conditional(value = {LinuxCondition.class})
@Configuration
public class MainConfig2 {
  /**
     * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
     * <p>
     * 如果系统是linux,给容器中注册("linux")
     * 如果是mac系统,给容器中注册("Mac")
     */
    @Bean("bill")
    @Conditional(MacCondition.class)
    public Person person01() {
        return new Person("Mac", 62);
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person02() {
        return new Person("linus", 48);
    }
}
5 ). @Import:  参数是一个数组,可以直接写bean的class, 或者ImportSelector,ImportBeanDefinitionRegistrar的实现类
			 ImportSelector: 返回需要导入的组件的全类名数组
			 ImportBeanDefinitionRegistrar:手动注册bean到容器中
	注意:使用@Import注册到容器的bean,默认【Id是全类名】

ImportSelector 实现类示例:

public class MyImportSecletor implements ImportSelector {

    /**
     * 返回值,就是到导入到容器中的组件全类名
     *
     * @param importingClassMetadata 当前标注@Import注解的类的所有注解信息
     * @return
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //方法不要返回null值
        return new String[]{"com.uu.anhusky.bean.Green"};
    }

ImportBeanDefinitionRegistrar的实现类

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类;
     * 		把所有需要添加到容器中的bean;调用
     * 		BeanDefinitionRegistry.registerBeanDefinition手工注册进来
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean definitionRed = registry.containsBeanDefinition("com.uu.anhusky.bean.Red");
        if(definitionRed){
            //容器中有red ,就加入蓝色
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
            registry.registerBeanDefinition("blue",beanDefinition);
        }
    }
}

Configuration配置如下

@Configuration
@Import({Color.class, Red.class, MyImportSecletor.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
}
6 ).  FactoryBean(工厂Bean)
		默认获取到的是工厂bean调用getObject创建的对象
		要获取工厂Bean本身,我们需要给id前面加一个&
      			&rainBowFactoryBean

FactoryBean实现类如下:

public class RainBowFactoryBean implements FactoryBean<RainBow> {
    public RainBow getObject() throws Exception {
        return new RainBow();
    }

    public Class<?> getObjectType() {
        System.out.println("RainBowFactoryBean...getObject...");
        return RainBow.class;
    }

    //是单例?
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    public boolean isSingleton() {
        return true;
    }
}

Configuration配置如下:

@Configuration
public class MainConfig2 {
 	@Bean
    public RainBowFactoryBean rainBowFactoryBean() {
        return new RainBowFactoryBean();
    }

}

3.2 生命周期类的注解

生命周期简介

1 ). bean生命周期介绍:
 	 		bean创建---初始化----销毁的过程
 	 容器管理bean的生命周期;
 	 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法

2 ). 	 构造(对象创建)
 	 		单实例:在容器启动的时候创建对象
 	 		多实例:在每次获取的时候创建对象

 	 BeanPostProcessor.postProcessBeforeInitialization
 	 初始化:
 	 		对象创建完成,并赋值好,调用初始化方法。。。
 	 BeanPostProcessor.postProcessAfterInitialization
3 ). 	 销毁:
 	 		单实例:容器关闭的时候
 	 		多实例:容器不会管理这个bean;容器不会调用销毁方法;
 

注解简介

1 ). @Bean注解中定义init和destory方法

public class MainConfigOfLifeCycle {

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

2 ). Bean 实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑)

public class AirPlane implements InitializingBean, DisposableBean {

    public AirPlane(){
         System.out.println("AirPlane --> construct");
    }

    public void destroy() throws Exception {
        System.out.println("AirPlane  ---->  destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("AirPlane  ---->  afterPropertiesSet");
    }
}

3 ). bean的方法中加入注解 @PostConstruct@PreDestroy

public class Dog {
    public Dog() {
        System.out.println("Dog constructor...");
    }
    
    //对象创建并赋值之后调用
    @PostConstruct
    public void init() {
        System.out.println("Dog....@PostConstruct...");
    }
    
    //容器移除对象之前
    @PreDestroy
    public void detory() {
        System.out.println("Dog....@PreDestroy...");
    }
}

4 ). BeanPostProcessor【interface】: bean的后置处理器,在bean初始化前后进行一些处理:

  • postProcessBeforeInitialization【method】:在初始化之工作
  • postProcessAfterInitialization【method】:在初始化之工作
    注:BeanPostProcessor:作用bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;spring底层大量使用此注解

加载顺序如下:

 BeanPostProcessor.postProcessBeforeInitialization
  初始化:
  		对象创建完成,并赋值好,调用初始化方法。。。
  BeanPostProcessor.postProcessAfterInitialization
  销毁:
  		单实例:容器关闭的时候
  		多实例:容器不会管理这个bean;容器不会调用销毁方法;
  
  
  遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
  一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
  
  BeanPostProcessor原理
  populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
  initializeBean
  {
	  applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	  invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
	  applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }

源码截图如下(可以通过打断点,查看堆栈调用信息)

AbstractAutoWireBeanFacotry 中的 doCreateBean 中的方法
在这里插入图片描述
初始化方法
在这里插入图片描述

4.源码地址

github地址

猜你喜欢

转载自blog.csdn.net/qq_21434959/article/details/83374488