位置: IT常识 - 正文

SpringBoot自动配置(装配)流程(springboot自动配置的注解)

编辑:rootadmin
源码分析 SpringBoot自动配置流程 ​ ​首先,我们要了解在@SpringBootApplication注解的内部,还具有@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan三个主要注解。 @SpringBootC ... 源码分析SpringBoot自动配置流程

推荐整理分享SpringBoot自动配置(装配)流程(springboot自动配置的注解),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:springboot自动配置文件,springboot自动配置原理(易懂),springboot自动配置文件,springboot自动配置,springboot自动配置原理,springboot自动配置流程,springboot自动配置,springboot自动配置原理,内容如对您有帮助,希望把文章链接给更多的朋友!

​首先,我们要了解在@SpringBootApplication注解的内部,还具有@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan三个主要注解。

@SpringBootConfiguration //标注该类是配置类,需要通过该类查找自动配置文件@EnableAutoConfiguration//自动配置的关键注解 其内部就是执行自动配置的代码@ComponentScan(excludeFilters = { //type : 要使用的筛选器类型 , classes 指定类型筛选器 //TypeExcludeFilter.class 筛选掉spirngBootApplication中被指定排除的配置类 @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), //AutoConfigurationExcludeFilter 将配置类与spirng.factories中的EnableAutoConfiguration对应的配置类进行对比匹配, 如果一致,会被排除掉@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) } )//扫描指定包的文件,将带有特定注解的类注入到Bean中public @interface SpringBootApplication {}@ComponentScan@ComponentScan注解主要用来扫描我们项目中的所有被像@service ,@Repository , @Controller,@configuration 等注解修饰的类, 将其注入到我们的IOC容器中,其中也包括我们的自动配置的文件:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Repeatable(ComponentScans.class) //表示可以重复利用@ComponentScan注解 /***作用 : 可以扫描指定的包,如果未指定包范围,将从该注解标注类所在的包进行扫描,* 与XML形式的<context:component scan>不同的是 @componentScan没有Config属性(true *就开启了属性自动注入的功能,如果是false就是关闭属性自动注入的功能),因为使用* @ComponentScan则默认所有的类都进行自动注入,会将所有扫描到的组件注入到IOC容器中*/public @interface ComponentScan {}@SpringBootConfiguration@SpringBootConfiguration 是SpringBoot替代@Configuration的注解,增加了自动找到配置的功能@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration //表示这是一个配置类 通过其间接了解到,@SpringBootApplication也是一个配置类/** * 用作Spring的标准@Configuration注解的替代,以便可以自动找到配置 */public @interface SpringBootConfiguration {}@EnableAutoConfiguration@EnableAutoConfiguration注解就是启动自动配置的关键注解,其内部使用了@import注解引入了一个AutoConfigurationImportSelector 自动配置类选择器@AutoConfigurationPackage //自动配置所在包注解,通过basePackages指定配置所在的包或者通过basePackageClasses指定基本包类,如果未指定,会默认注册指定注解类所在的包//AutoConfigurationImportSelector自动配置选择器,实现了ImportSelector接口,重写了selectImports方法,自动配置的具体实现就在其内部进行//ImportSelector接口作用 :根据给定的选择条件(通常是一个或多个注解属性)确定应导入哪个配置类。@Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}SpringBoot自动配置(装配)流程(springboot自动配置的注解)

​在其内部重写了selectImports方法, 通过调用getAutoConfigurationEntry()方法根据传入的注解元数据,获取到自动配置类的实体,而后从实体中获取具体的配置信息,配置信息在实体内部是一个list集合,所以将其转化为String数组后返回。

//为方便显示及理解,省略了该类实现的部分接口和具体的代码实现,需要了解可进入源码查看public class AutoConfigurationImportSelector implements DeferredImportSelector { @Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {//AnnotationMetadata: 配置类的注解元数据,也就是配置类的注解信息 //调用getAutoConfigurationEntry()方法根据传入的注解信息,获取并返回自动配置类的实体AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); //从配置实体中获取具体的配置信息,返回的是一个list集合,而后通过toStringArray()方法转存到字符串数组中返回return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}getAutoConfigurationEntry()//可以先看下获取的大致流程,而后进入查看器方法内部的具体实现protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {//1. 从注解元数据中获取注解的相应属性,将相应属性存储到map中返回 //1.1AnnotationAttributes是一个Map集合,其继承了LinkedHashMapAnnotationAttributes attributes = getAttributes(annotationMetadata); //2. 通过getCandidateConfigurations()方法根据注解元数据和注解的属性信息 获取应该进行自动配置的类名,可以理解为自动配置候选项List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//2.1 通过removeDuplicates()方法对自动配置的类名进行去重处理 configurations = removeDuplicates(configurations); //3. 根据注解元数据和注解属性获取到需排除配置项Set<String> exclusions = getExclusions(annotationMetadata, attributes); //3.1检查是否有无效的排除类存在checkExcludedClasses(configurations, exclusions); //3.2从自动配置候选项中删除需要排除的配置项 configurations.removeAll(exclusions); //4. 调用getConfigurationClassFilter()方法获取到获取配置的所有AutoConfigurationImportFilter的实现类(对spring.factories进行过滤的类),调用filter方法对配置文件进行筛选,而后返回需要自动配置的类configurations = getConfigurationClassFilter().filter(configurations); //5. 根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件,最后根据多次过滤、判重返回配置类合集fireAutoConfigurationImportEvents(configurations, exclusions); //6. 创建一个新的配置实体ConfigurationEntry并返回,包含需要配置项configurations,和被排除配置项exclusionsreturn new AutoConfigurationEntry(configurations, exclusions);}

下面了解以下getAutoConfigurationEntry()内部调用的方法源码

从注解元数据中返回相应的属性信息

getAttributes(AnnotationMetadata annotationMetadata)

/** * 从注解元数据中返回相应的属性信息。 * param 注解元数据信息 * return 注解元数据的属性信息 其本质是一个Map集合 */protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { /** * getAnnotationClass() 返回源注解类 -->EnableAutoConfiguration.class * getAnnotationClass().getName(); 获取注解类的完全限定类名*/ String name = getAnnotationClass().getName(); /** * metadata.getAnnotationAttributes(String annotationName,boolean classValuesAsString) * 作用: 检索给定注解的属性 * @param1 要查找的注解类的完全限定类名 * @param2 是否将类引用转换为String类名,以便作为返回Map中的值公开,而不是可能必须首先加载的类引用 * *AnnotationAttributes.fromMap(@Nullable Map<String, Object> map); * 基于给定的集合返回AnnotationAttributes实例。如果该集合是AnnotationAttributes实例或其子类,它将被强制转换并立即返回,而无需创建新实例。否则,将通过将提供的映射传递给AnnotationAttributes的map)的构造函数来创建新实例。其参数是一个Map类型的注解属性数据源,也就是attrbuties */ AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true)); /** *Assert类 是一个协助验证参数的断言实用程序类,详细使用可以查看其源码 * Assert.notNull(@Nullable Object object, Supplier<String> messageSupplier)方法 * 作用 : 判断对象是不是null, 如果为null,报错提示 * param1 : 要进行判断的对象 * param2 : 如果为null,要给予返回的异常信息 */Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()+ " annotated with " + ClassUtils.getShortName(name) + "?");//返回注解元数据的属性信息map集合 return attributes;}

获取应该进行自动配置的类名

getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes);

/** *根据注解元数据和注解的属性信息 获取应该进行自动配置的类名,可以理解为自动配置的候选项(初选名单) *param1 元注解数据 *param2 元注解数据的属性信息集合 *return List<String> 存储的数据就是应该继续宁自动配置的类名*/protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //SpringFactoriesLoader是一个用于框架内部使用的通用工厂加载机制List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}对自动配置项进行去重处理1 configurations = removeDuplicates(configurations);对自动配置的类名进行去重处理//通过removeDuplicates()方法对自动配置的类名进行去重处理//利用Set集合数据不重复特性,将list集合存储到LinkedHashSet集合中进行去重处理,而后再将去重的结果存储到List集合中返回 protected final <T> List<T> removeDuplicates(List<T> list) {return new ArrayList<>(new LinkedHashSet<>(list));} 从自动配置项中筛选被排除配置项configurations.removeAll(exclusions);//从自动配置候选项中筛选需排除配置项protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { //创建一个需排除配置项集合excludedSet<String> excluded = new LinkedHashSet<>(); //从属性信息集合中获取到key为exclude的值,将其存储到excluded集合中excluded.addAll(asList(attributes, "exclude")); //从属性信息集合中获取到key为excludeName的数据,返回的是一个字符串数组,返回后将其转化为List集合,存储到excluded集合中excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName"))); /** * getExcludeAutoConfigurationsProperty(): *返回 spring.autoconfigure.exclude 属性排除的自动配置 */ excluded.addAll(getExcludeAutoConfigurationsProperty());return excluded;}-----------------------------------------------------------------------------------------/*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/-----------------------------------------------------------------------------------------//attributes.getStringArray("excludeName")public String[] getStringArray(String attributeName) {return getRequiredAttribute(attributeName, String[].class);}

exclude 和excludeName 都是指定某些类在项目启动时不进行自动配置,其一般在@SpringBootApplication 中进行配置。

检查是否有无效的排除类存在1 configurations.removeAll(exclusions);//检查是否有无效的排除类存在private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {//创建一个用于存储无效配置项的集合 List<String> invalidExcludes = new ArrayList<>(exclusions.size());//循环需排除配置项 for (String exclusion : exclusions) { //根据类的全限定名判断该类是否存在且可以被加载,并且 需排除配置项集合是否包含该类if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) { //如果存在,且不再需排除配置项的集合中,将其添加到无效配置项集合中invalidExcludes.add(exclusion);}} //如果无效配置项集合不为空,说明存在无效配置项if (!invalidExcludes.isEmpty()) { //处理无效配置项 --> 报错 IllegalStateException 无效状态异常handleInvalidExcludes(invalidExcludes);}}-----------------------------------------------------------------------------------------/*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/-----------------------------------------------------------------------------------------/** *ClassUtils.isPresent() 根据类名称判断是否存在并且可以加载,如果类或其依赖项之一不存在或无法 加载返回false * param1 className 要检查的类的名称 * param2 classLoader 要使用的类加载器(如果为null,表示默认的类加载器) */public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {try { //forName(类名称,类加载器) 用于替换Class.forName()方法, 并且还返回所提供名称的类实例forName(className, classLoader);return true;}catch (IllegalAccessError err) {throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +className + "]: " + err.getMessage(), err);}catch (Throwable ex) {// Typically ClassNotFoundException or NoClassDefFoundError...return false;}}从自动配置项中删除需要被排除的配置项2 configurations.removeAll(exclusions);/** *从自动配置候选项中删除需要排除的配置项 * 集合A.removeAll(集合B);作用就是从集合A数据项中删除掉集合B所包含的元素 */configurations.removeAll(exclusions);创建配置类过滤器对配置项进行筛选过滤configurations = getConfigurationClassFilter().filter(configurations);//通过getConfigurationClassFilter()获取所有AutoConfigurationImportFilter的实现类(对spring.factories进行过滤的类),而后调用filter方法对配置文件进行筛选,而后返回需要自动配置的类configurations = getConfigurationClassFilter().filter(configurations);-----------------------------------------------------------------------------------------/*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/-----------------------------------------------------------------------------------------//获取配置类过滤器private ConfigurationClassFilter getConfigurationClassFilter() { //this.configurationClassFilter当前类的配置类过滤器是不是为null if (this.configurationClassFilter == null) { // 获取AutoConfigurationImportFilter过滤器的实现类集合 List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters(); for (AutoConfigurationImportFilter filter : filters) {invokeAwareMethods(filter); //在监听器注入是有描述,两者使用的同一方法} //实例化配置类过滤器 ,根据 类加载器和过滤器实现类实例化配置类过滤器 //ConfigurationClassFilter类内部含有类加载器和过滤器实现类集合的属性this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);} //返回配置类过滤器return this.configurationClassFilter;}//getAutoConfigurationImportFilters(); 获取AutoConfigurationImportFilter过滤器的实现类集合protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() { /** * List<T> loadFacotries(Class<T> factoryType, @Nullable ClassLoader classLoader) * 使用给定的类加载器从{"META-INF/spring.factories"}加载并实例化指定过滤器工厂的实现类 * 在结果返回之前会对结果集进行排序 * param1 表示工厂的接口或者抽象类,-->生成其子类 * param2 当前类的类加载器-->用于加载抽象类的实现类 * return 返回指定接口或者抽象类的实现类List集合 */ //返回AutoConfigurationImportFilter实现类的集合return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);}//configurations = getConfigurationClassFilter().filter(configurations);//过滤 自动配置项List<String> filter(List<String> configurations) {long startTime = System.nanoTime(); //将将配置转化为字符串数组String[] candidates = StringUtils.toStringArray(configurations);boolean skipped = false;for (AutoConfigurationImportFilter filter : this.filters) { //循环过滤条件与配置项进行一一匹配,剔除掉条件不成立的配置项boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);for (int i = 0; i < match.length; i++) {if (!match[i]) {candidates[i] = null;skipped = true;}}} //如果全都符合则直接返回配置项集合if (!skipped) {return configurations;} //创建结果集集合List<String> result = new ArrayList<>(candidates.length);for (String candidate : candidates) {//配置项不为null就添加到配置类中 if (candidate != null) {result.add(candidate);}} //返回结果return result;}}创建配置类监听器对自动配置进行监听fireAutoConfigurationImportEvents(configurations, exclusions);//根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件,最后根据多次过滤、判重返回配置类合集private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { //从{ "META-INF/spring.factories"}加载并实例化自动配置类监听器 AutoConfigurationImportListener的实现类集合List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); //如果监听器不为空的话if (!listeners.isEmpty()) //创建fireAutoConfigurationImportEvents监听事件 AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions); //循环遍历 判断listener是否是 Aware 通过Aware接口 实现对bean各阶段的监听for (AutoConfigurationImportListener listener : listeners) { //通过Aware类的实现类对监听器进行配置 -->解这一模块,可以重点关注以下Aware接口invokeAwareMethods(listener); //进行自动配置的导入 event 到自动配置时进行的事件-->对自动配置的监听 listener.onAutoConfigurationImportEvent(event);}}}//根据Aware类对bean的各阶段进行监听配置private void invokeAwareMethods(Object instance) { //判断监听器是否是Aware或其实现类if (instance instanceof Aware) { if (instance instanceof BeanClassLoaderAware) { /** * BeanClassLoaderAware 允许bean知道bean的回调ClassLoader,即当前bean工厂用来加载bean类的类加载器。这主要是由框架类来实现的,这些框架类必须通过名称来获取应用程序类,尽管它们本身可能从共享类加载器加载的。 * 方法 setBeanClassLoader(ClassLoader classLoader); *将bean的类加载器 提供给bean实例的回调。 * 作用范围: 在填充普通bean属性之后,初始化回调之前调用 */((BeanClassLoaderAware) instance).setBeanClassLoader(this.beanClassLoader);}if (instance instanceof BeanFactoryAware) { /** * BeanFactoryAware 表示接口知道其拥有的{BeanFactory}的bean实现。 *注意 :大多数的bean都可以通过属性注入和构造注入接收对bean的引用 *方法 :setBeanFactory(BeanFactory beanFactory) *向bean实例提供拥有工厂的回调。 * 作用范围: 在填充普通bean属性之后,初始化回调之前调用, */((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);}if (instance instanceof EnvironmentAware) { /** * EnvironmentAware 表示该接口可以收到其运行环境的通知 *方法 :setEnvironment(Environment environment); *设置此组件的运行环境 */((EnvironmentAware) instance).setEnvironment(this.environment);}if (instance instanceof ResourceLoaderAware) { /** * ResourceLoaderAware 接口,该接口可以收到该对象运行的ResourceLoader资源封装类加载器 *方法 :setResourceLoader(ResourceLoader resourceLoader); *作用 :设置此对象运行的ResourceLoader。可能是一个ResourcePatternResolver *作用范围: 在填充普通bean属性之后,初始化回调之前调用 */((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);}}}创建新的配置实体后返回SelectImports方法体内return new AutoConfigurationEntry(configurations, exclusions);根据需要配置项和被排除项实例化新的配置实体,并返回AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {this.configurations = new ArrayList<>(configurations);this.exclusions = new HashSet<>(exclusions);}将配置实体中的配置信息转化为字符串数组返回,完成注入//获取最终要导入的配置实体AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); //从配置实体中获取具体的配置信息,返回的是一个list集合,而后通过toStringArray()方法转存到字符串数组中返回return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

本笔记个人查看源码时根据立即理解缩写,如有错误可留言告知,谢谢

本文链接地址:https://www.jiuchutong.com/zhishi/303680.html 转载请保留说明!

上一篇:phpcms js乱码怎么解决(如何解决php乱码)

下一篇:小米开放平台逆向工程(小米开发回稳定)

  • 抖音钱包零钱怎么买东西(抖音钱包零钱怎么充值抖币)

    抖音钱包零钱怎么买东西(抖音钱包零钱怎么充值抖币)

  • oppo手机正在运行的程序怎么设置(OPPO手机正在运行的服务)

    oppo手机正在运行的程序怎么设置(OPPO手机正在运行的服务)

  • 苹果手机收藏的文件在哪里可以找到(苹果手机收藏的照片在哪里可以找到)

    苹果手机收藏的文件在哪里可以找到(苹果手机收藏的照片在哪里可以找到)

  • 网易云季卡是几个月(网易云音乐年卡什么时候最便宜)

    网易云季卡是几个月(网易云音乐年卡什么时候最便宜)

  • 路由器不亮(路由器不亮怎么回事)

    路由器不亮(路由器不亮怎么回事)

  • 蓝底照片怎么用手机拍(蓝底照片怎么用苹果手机拍)

    蓝底照片怎么用手机拍(蓝底照片怎么用苹果手机拍)

  • 小米手环洗澡可以带吗(小米手环洗澡的时候可以带吗)

    小米手环洗澡可以带吗(小米手环洗澡的时候可以带吗)

  • windows许可证过期有什么影响(windows许可证过期是什么意思)

    windows许可证过期有什么影响(windows许可证过期是什么意思)

  • 一寸照片的像素是多少乘多少(一寸照片的像素和尺寸怎么调整)

    一寸照片的像素是多少乘多少(一寸照片的像素和尺寸怎么调整)

  • 微信账单怎么只有三个月(微信账单怎么只看支出)

    微信账单怎么只有三个月(微信账单怎么只看支出)

  • 华为挖孔屏手机有哪几款(华为 挖孔)

    华为挖孔屏手机有哪几款(华为 挖孔)

  • 屏幕dpi什么意思(屏幕dpi越高越好还是越低越好)

    屏幕dpi什么意思(屏幕dpi越高越好还是越低越好)

  • 手机浏览器打不开网页是什么原因(手机浏览器打不开某些网站)

    手机浏览器打不开网页是什么原因(手机浏览器打不开某些网站)

  • 抖音里面互相关注是什么意思(抖音里面互相关注的人为什么看不了他发的抖音)

    抖音里面互相关注是什么意思(抖音里面互相关注的人为什么看不了他发的抖音)

  • windows7常用附件有哪些(win7常用的附件)

    windows7常用附件有哪些(win7常用的附件)

  • 如何把通讯录转到新手机上(如何把通讯录转到微信)

    如何把通讯录转到新手机上(如何把通讯录转到微信)

  • ipad如何清理垃圾(如何清理ipad中的垃圾)

    ipad如何清理垃圾(如何清理ipad中的垃圾)

  • 怎么加入饿了么骑手(怎么加入饿了么商家入驻)

    怎么加入饿了么骑手(怎么加入饿了么商家入驻)

  • 哔哩哔哩视频怎么转成mp4(哔哩哔哩视频怎么保存到电脑)

    哔哩哔哩视频怎么转成mp4(哔哩哔哩视频怎么保存到电脑)

  • 应和的意思(附声应和的意思)

    应和的意思(附声应和的意思)

  • 电子照片怎么做(电子照片怎么做成jpg格式)

    电子照片怎么做(电子照片怎么做成jpg格式)

  • 8p单换外屏有影响吗(8p换了外屏有什么毛病没)

    8p单换外屏有影响吗(8p换了外屏有什么毛病没)

  • 三星怎么看电池损耗(三星怎么看电池循环次数)

    三星怎么看电池损耗(三星怎么看电池循环次数)

  • 企业微信如何远程打卡(企业微信如何远距离打卡)

    企业微信如何远程打卡(企业微信如何远距离打卡)

  • 使用 TF-IDF 算法将文本向量化(tf-idf计算)

    使用 TF-IDF 算法将文本向量化(tf-idf计算)

  • Windows OpenGL 图像饱和度调节(opengl 图形)

    Windows OpenGL 图像饱和度调节(opengl 图形)

  • 制造业做贸易出口可以退税吗
  • 亏损企业如何填报企业所得税
  • 税收筹划分为哪几类
  • 办公室电话费计入什么科目
  • 增值税销项税的计税依据(销售额)包括()
  • 提现的现金流量代码是什么
  • 汇算清缴调表不调账调的是哪张表
  • 开具红字信息表后怎么开负数发票
  • 报废过期产品怎么做会计分录
  • 土地增值税预征率
  • 库存商品进项税额转出分录怎么写
  • 当月预交增值税时所属期选了上期怎么办
  • 土地税退税做什么分录
  • 以前年度应付款确认不再支付应调整到哪个科目?
  • 复利现值系数和普通年金现值系数关系
  • 资产减值损失进利润表吗
  • 增值税专用发票验票
  • 营改增后固定资产报废处置收入计税
  • 餐饮外卖的经营范围是什么项目
  • 提供建筑服务应在发票备注栏注明
  • 计划成本法如何计算材料成本差异率
  • 契税和印花税入哪个科目
  • 银行存款缴税
  • 小规模企业低值易耗品摊销方法
  • 原材料报废怎么记账
  • 一般纳税人减免性质代码怎么填写
  • win10鼠标在哪
  • PHP:mb_convert_encoding()的用法_mbstring函数
  • 异常发票怎么处理
  • 详解php语言最牛的语言
  • win11怎么录屏游戏
  • 房地产评估计费
  • 施工企业工程结算
  • PHP:pg_connection_status()的用法_PostgreSQL函数
  • 审核凭证要注意哪些问题
  • php的file函数
  • 带息应收票据应于收到或开出或承兑时
  • 不确认收入要结转成本吗
  • thinkphp excel
  • 出口增值税申报了
  • 分公司二季度安全生产分析会内容
  • 客户少给了钱怎么要
  • 验证码php代码
  • 帝国cms首页怎么打开
  • mysql数据库高可用方案
  • 伤残补助金和工资一样吗
  • 培训属于什么服务
  • 百万级别数据库mysql
  • 外购商品用于宣传需要缴纳增值税吗
  • 营业外支出账户核算的主要内容有
  • 购销合同没注明合同有效期
  • 增值税发票抵扣联丢失怎么办
  • 购买生产原料的支出
  • 关税的计税方式一般可以分为
  • 外币报表折算差额会计分录
  • 集团内部资产无偿划转是否缴纳印花税
  • 高新技术企业享受优惠时间
  • mysql group order
  • unix系统什么样子
  • mfc100udll
  • Linux系统防火墙的命令
  • 如何在Windows下移动文件
  • windows10 uac关闭
  • windows7旗舰版怎么打字
  • 电脑自带的groove音乐用不了
  • perl 批量注释
  • python网络编程视频教程
  • python 执行命令
  • cocos2dx 4.0
  • 原生js实现节日变化
  • oracle中提取日期时间的特定部分
  • android的消息机制
  • androidmvvm框架
  • 基于JAVASCRIPT实现的可视化工具是
  • 不同地区的社保卡通用吗
  • 叉车需要手续吗
  • 虚假新闻造成的真实伤害
  • 12366纳税服务热线
  • 居间服务费税收优惠政策
  • 发票机怎么测试打印
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设