Spring Bean生命周期之属性赋值阶段详解

目录
  • 前言
  • 属性自动装配
  • 属性赋值前回调
  • 属性的真正赋值
  • 总结

前言

上节在谈论Bean的实例化过程时,在说明实例化后阶段时只是粗略地看了一下populateBean,并未展开分析。本节接着populateBean开始分析对象赋值阶段的事情。

populateBean其实主要做了以下几件事:

  • Bean实例化后回调,来决定是否进行属性赋值 (上节分析过了)
  • 对属性进行自动装配
  • InstantiationAwareBeanPostProcessor属性赋值前回调
  • 属性的真正赋值
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		//省略无关代码
		// 1、 Bean实例化后回调,来决定是否进行属性赋值
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
        //2、对属性进行自动装配
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		//3、InstantiationAwareBeanPostProcessor属性赋值前回调
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		//省略无关代码
		if (pvs != null) {
		  //属性的赋值
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

属性自动装配

PropertyValues 对bd中属性的封装,可以理解为bd中属性键值均由其保存,其常用实现类为MutablePropertyValues,在BeanDefinition的概述及使用 有介绍其使用,可点击查看

        //这里的bd是已经执行过合并BeanDefinition操作了
        //如果bd存在属性 则获取
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		//获取bd的自动注入模式
		//注入模式有四种:
		//1.构造函数注入 2、按照名称注入 3、按照类型注入 4、不注入(默认,依然可能会被注解驱动注入)
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		//如果是按名称注入或类型注入时
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			//按名称注入
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			    //按类型注入,基本上这种比较常用
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

下面我们分别来大致看下autowireByNameautowireByType 熟悉下实现原理

autowireByName

protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
		//获取属性名称
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//遍历属性名称
		for (String propertyName : propertyNames) {
		    //如果属性名称已在beanDefinitionMap中,说明其是bd 并已被注册待IoC容器
			if (containsBean(propertyName)) {
			    //根据名称获取其bean对象
				Object bean = getBean(propertyName);
				//以键值方法赋值到pvs
				pvs.add(propertyName, bean);
				// 这里是维护dependentBeanMap、dependenciesForBeanMap两个集合,
				// 这里不再展开 在说到LifecycleProcessor时再展开
				registerDependentBean(propertyName, beanName);
				//省略日志输出
			}
			else {
				//省略日志输出
			}
		}
	}

autowireByType

按类型注入稍显复杂些,但流程上与按名称注入类似

protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
		//类型转换器
		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}
		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		//依然是获取属性名称
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//遍历属性名称
		for (String propertyName : propertyNames) {
			try {
			    //获取属性描述对象
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				//不对Object类型做注入,因此这里判断条件如下
				if (Object.class != pd.getPropertyType()) {
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//解析依赖
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
					//以键值方法赋值到pvs
						pvs.add(propertyName, autowiredArgument);
					}
					for (String autowiredBeanName : autowiredBeanNames) {
					 // 这里是维护dependentBeanMap、dependenciesForBeanMap两个集合,
				     // 这里不再展开 在说到LifecycleProcessor时再展开
						registerDependentBean(autowiredBeanName, beanName);
						//省略日志输出
					}
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				//省略异常信息
		}
	}

接下来我们进入到resolveDependency,大致分析下解析依赖的主要流程

DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    //如果依赖类型是Optional
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
  //如果依赖类型是ObjectFactory或ObjectProvider
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
   //如果依赖类型是Inject
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
        //实际执行解析依赖的逻辑代码
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}
	@Nullable
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}
			//获取依赖类型
			Class<?> type = descriptor.getDependencyType();
      //获取依赖类型的默认值,如@Value注解 可提供默认值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
        //如果默认值是String类型
				if (value instanceof String) {
          //从配置文件中解析出指定key的数据
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
					value = evaluateBeanDefinitionString(strVal, bd);
				}
        //类型转换器 用于转换类型,如配置文件中声明的是字符串类型的数字,而java中使用Integer接收,则类型转换器就派上用场了
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
			//解析出类型是Stream、Map、数组、Collection等集合类型的依赖。解析的思路很类似 即去IoC容器中 查找集合类实际泛型对应的Bean
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			//这里主要是查找单实例Bean的,如果某个类型的Bean有多个,这里会被全部查找出来,因此使用Map接收
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}
			String autowiredBeanName;
			Object instanceCandidate;
      //如果查找出的Bean有多个,
			if (matchingBeans.size() > 1) {
        //找出标注了@Primary的那个Bean名称,作为查找出的Bean
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
            //如果没有@Primary注解标注,那么抛出NoUniqueBeanDefinitionException
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
        //如果查找出的Bean只有1个 那么说明找到了。
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

可以看出resolveDependency方法还是很强大的,无论是单一类型对象还是集合类型对象,无论是Optional类型还是延迟加载ObjectFactory类型 其均可以解析出来。

属性赋值前回调

         //boolean值 判断有没有InstantiationAwareBeanPostProcessor存在
         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
         // 这是 是否依赖检查的标记 不是我们此次的重点
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		PropertyDescriptor[] filteredPds = null;
		//IoC容器中如果存在InstantiationAwareBeanPostProcessor
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			//遍历BeanPostProcessor,找到InstantiationAwareBeanPostProcessor类型
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//postProcessProperties、postProcessPropertyValues两个方法含义类似。如果postProcessProperties未被重写 则执行postProcessPropertyValues方法
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}

这里针对一个小案例说明下postProcessPropertyValuespostProcessProperties的使用

需求:将注入的user对象中name属性由wojiushiwo修改为abc

实体对象User

@Data
@ToString
public class User {
    private String name;
    private Integer age;
    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
public class MyInstantiationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if(ObjectUtils.nullSafeEquals("user",beanName) && User.class.equals(bean.getClass())){
            final MutablePropertyValues propertyValues;
            if(pvs instanceof MutablePropertyValues){
                propertyValues= (MutablePropertyValues) pvs;
            }else{
                propertyValues=new MutablePropertyValues();
            }
            if(propertyValues.contains("name")){
                propertyValues.removePropertyValue("name");
                propertyValues.addPropertyValue("name","abcd");
            }
            return propertyValues;
        }
        return null;
    }
}
public class BeanPostProcessDemo {
    public static void main(String[] args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("name", "wojiushiwo");
        beanDefinitionBuilder.addPropertyValue("age", 20);
        // 获取 AbstractBeanDefinition
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        // 附加属性(
        beanDefinition.setAttribute("name", "我是附加属性");
        // 当前 BeanDefinition 来自哪里(辅助作用)
        beanDefinition.setSource(BeanPostProcessDemo.class);
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.addBeanPostProcessor(new MyInstantiationBeanPostProcessor());
        // 注册 User 的 BeanDefinition
        beanFactory.registerBeanDefinition("user", beanDefinition);
        User user = beanFactory.getBean("user", User.class);
        System.out.println(user);
    }
}

输出结果:

User(name=abcd, age=20)

属性的真正赋值

    if (pvs != null) {
            //将从前面步骤得到的pvs 赋值到beanWrapper中以实现属性赋值,这部分具体源码这里不展开了
			applyPropertyValues(beanName, mbd, bw, pvs);
		}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Spring Bean生命周期之BeanDefinition的合并过程详解

    目录 前言 BeanDefinition的合并源码分析 总结 写在前面 注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE 前言 书接上文,BeanDefinition注册到IoC容器后,紧接着就是要使用Bean了,要使用必须先要获取Bean,这里我们就以DefaultListableBeanFactory#getBean方法来引出本次讨论的内容:BeanDefinition的合并 通过前面的章节我们了解到了BeanD

  • Spring Bean生命周期之Bean的注册详解

    目录 前言 BeanFactory的继承体系 Bean的注册 alias别名的注册 总结 前言 上篇文章介绍了Bean元信息的配置与解析过程,限于篇幅Bean注册过程就没展开. 这里主要围绕BeanDefinitionReaderUtils#registerBeanDefinition展开分析下Bean注册过程 public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinit

  • Spring中如何使用@Value注解实现给Bean属性赋值

    目录 属性赋值 @Value注解的定义: 测试 1.在添加了Spring依赖的Maven项目中创建 2.在resources目录下创建一个配置文件person.properties 3.创建配置类 4.创建测试类进行测试 5.测试结果: 如何给Bean的属性赋值(注入) 1.通过构造方法设置值. 2.设置注入(通过set方法) 属性赋值 只用Spring注解开发的时候,可以使用@Value搭配@PropertySource注解进行给Bean的属性进行赋值. @Value @Value注解的定义:

  • Spring Bean生命周期之Bean的实例化详解

    目录 前言 实例化前阶段 实例化阶段 实例化后阶段 总结 前言 上一节说到了BeanDefinition的合并过程,这节该说Bean的实例化过程了.根据AbstractAutowireCapableBeanFactory#createBean源码逻辑 可将实例化过程分为实例化前阶段.实例化过程.实例化后阶段. 实例化前阶段 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[]

  • Spring Bean生命周期之Bean元信息的配置与解析阶段详解

    目录 BeanDefinitionReader体系 BeanDefinitionReader接口定义 元信息配置与解析方式 XmlBeanDefinitionReader元信息解析源码分析 AnnotatedBeanDefinitionReader元信息解析源码分析 总结 写在前面 注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE 虽然Bean的创建可以采用BeanDefinition API 也可以直接采用注解方式

  • Spring Bean生命周期之属性赋值阶段详解

    目录 前言 属性自动装配 属性赋值前回调 属性的真正赋值 总结 前言 上节在谈论Bean的实例化过程时,在说明实例化后阶段时只是粗略地看了一下populateBean,并未展开分析.本节接着populateBean开始分析对象赋值阶段的事情. populateBean其实主要做了以下几件事: Bean实例化后回调,来决定是否进行属性赋值 (上节分析过了) 对属性进行自动装配 InstantiationAwareBeanPostProcessor属性赋值前回调 属性的真正赋值 protected

  • Spring Bean生命周期详细分析

    目录 前言 一.Bean的介绍 什么是Bean Bean的生命周期 Bean的作用域 二.详细过程 1. Bean的实例化 2. InstantiationAwareBeanPostProcessor 3. 设置属性(依赖注入) 4. 注入Aware接口 5. BeanPostProcessor的postProcessBeforeInitialzation方法 6. InitializingBean与init-method 7. BeanPostProcess的postProcessAfterI

  • 全面详解Spring Bean生命周期教程示例

    目录 Spring 中 Bean 的生命周期 Bean 的实例化 构造方法注入 工厂方法注入 Bean 的属性赋值 setter注入 构造方法注入 Bean 的初始化 初始化方法 InitializingBean 接口 Bean 的销毁 销毁方法 DisposableBean 接口 总结 Spring 中 Bean 的生命周期 是当今最流行的 Java 开发框架之一,其强大的 Bean容器机制是其中的核心之一.Bean 是指在 Spring 容器中被管理的对象,它们可以被注入到其他对象中,也可以

  • 谈谈我对Spring Bean 生命周期的理解

    前言 Spring的ioc容器功能非常强大,负责Spring的Bean的创建和管理等功能.而Spring 的bean是整个Spring应用中很重要的一部分,了解Spring Bean的生命周期对我们了解整个spring框架会有很大的帮助. BeanFactory和ApplicationContext是Spring两种很重要的容器,前者提供了最基本的依赖注入的支持,而后者在继承前者的基础进行了功能的拓展,例如增加了事件传播,资源访问和国际化的消息访问等功能.本文主要介绍了ApplicationCo

  • Spring生命周期回调与容器扩展详解

    本篇主要总结下Spring容器在初始化实例前后,提供的一些回调方法和可扩展点.利用这些方法和扩展点,可以实现在Spring初始化实例前后做一些特殊逻辑处理. 下面主要介绍: 类级别的生命周期初始化回调方法init-method配置.InitializingBean接口和PostConstruct注解 容器级别的扩展BeanPostProcessor接口和BeanFactoryPostProcessor接口 1.类级别生命周期回调 1.1init-method 参照:Springbeanxsdin

  • 浅谈Spring bean 生命周期验证

    一.从源码注释看bean生命周期 从JDK源码上看,BeanFactory实现类需要支持Bean的完整生命周期,完整的初始化方法及其标准顺序(格式:接口 方法)为: 1.BeanNameAware setBeanName 设置bean名称 2.BeanClassLoaderAware setBeanClassLoader 设置bean类加载器 3.BeanFactoryAware setBeanFactory 设置bean工厂 4.EnvironmentAware setEnvironment

  • Spring Bean生命周期源码原理图解

    概述 spring流行了很长时间了,是一个用java编写的轻量级框架,受到了很多公司及程序员的欢迎,Bean生命周期是一个对象从实例化开始到销毁的全过程,了解生命周期是很有必要的. 重要性 spring的生命周期是比较复杂的,只有了解其过程及原理才能更好的扩展程序. 源码剖析生命周期过程bean的实例化 属性填充及Aware接口检测设置依赖 如果容器自定义了BeanpostProcessor的实现类,则执行处理器相应的前置处理 bean实现了初始化接口InitlializingBean,则会执行

  • Vue生命周期和钩子函数的详解与经典面试题

    目录 1. vue生命周期 2.钩子函数 2.1 分为4大阶段8个方法: 2.2 初始化阶段 2.3 挂载阶段 2.4 更新阶段 2.5 销毁阶段 面试题: 总结 1. vue生命周期 一组件从 创建 到 销毁 的整个过程就是生命周期 Vue 实例从创建到销毁的过程,就是生命周期.也就是从开始创建.初始化数据.编译模板.挂载Dom→渲染.更新→渲染.卸载等一系列过程,我们称这是 Vue 的生命周期. 2.钩子函数 Vue 框架内置函数,随着组件的生命周期阶段,自动执行,特定的时间点,执行特定的操

  • Android开发中Activity的生命周期及加载模式详解

    本文给大家介绍Activity的生命周期,如果大家学习过iOS的小伙伴的话,Activity的生命周期和iOS中ViewController的生命周期非常类似.生命周期,并不难理解.一个人的生命周期莫过于生老病死,花儿的生命周期就是花开花谢了.在Android中Activity的生命周期莫过于Activity的创建到消亡的过程了.本篇博客就会介绍Activity生命周期中的不同阶段,通过实例的形式来窥探一下Activity的生命周期.搞明白Activity的生命周期是至关重要的,因为只有搞明白每

随机推荐