Springboot自动装配原理(pom.xml配置解析,项目自动化原理的实现流程)

安装一个Springboot项目

先从pox.xml中配置进行理解

依赖一:

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.7.9</version>
  </parent>

依赖中的父类中的父类(最顶层): 存放着所有项目工程所能够使用的依赖版本

 依赖二:项目启动器

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

注意:项目启动的环境有很多,只需要修改下面的xxxx内容即可

<artifactId>spring-boot-starter-XXXX</artifactId>

例如:log4j,web,jdbc,aop等等

如果导入这种依赖就会自动将该项目中使用的自动导入依赖,减少了在spring系列各种配置文件的配置流程,极大的解放了双手,通过项目中本身所搭配的环境,来实现代码的运行。

在spring boot框架中有很多很多自动配置类,他都存放在一个已经打包完成的spring jar包中,所有的自动配置类放在次jar包内,只需要进行调用即可

 

自动配置实现流程: 上面说的是自动配置类存放的位置,接下来我们需要去调用spring.factories中的自动配置类,将标注注解为@configuration的配置类进行反射实例化,并将这些汇总到一个IOC容器中在项目中进行使用。

自动装配配置注解

@SpringBootApplication注解主配置类程序的主入口,开启项目的钥匙

那么凭什么这一个注解就可以打开spring boot项目的呢?

打开注解,看下面三个注解,这三个注解为@SpringBootApplication提供了大部分的功能,当然这么牛逼的注解不光只有这几个注解,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

上面这四个注解则是生成注解必不可少的一部分,只要是注解就必不可少的一部分吧。但是对与自动装配却是无关紧要。

@SpringBootConfiguration

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.boot;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

点进去,我们发现了一个特别熟悉的注解@Configuration ,主要实现的作用的则是,将当前类组为一个配置类相当于spring中的配置文件,将此类交给spring中ioc容器进行统一的管理

注意:在理论意义上spring boot是在spring进行的不断地框架化,它保留了在spring项目中能够使用得到大部分功能,所以注解就可以直接拿来进行用。

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)

@ComponentScan

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";

    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

 @ComponentScan这个注解是不是看着有一丝熟悉,如果你学过spring或者springmvc你在看这个注解就会感到见过,在spring项目地配置文件中,你是否配置过这样的一行代码

 context:component-scan 对,不错这个注解实现地就是扫描项目中配置地那些类,亦可以说添加@Component,@Service,@Controller 等注解的类。

上面的两个注解起到的环境搭配的作用,要是想要实现自动装配,靠的还是注解

@EnableAutoConfiguration   auto便表示自动化的意思,这个注解则是实现自动化的关键所在

打开这个注解,注解内部主要的功能代码则是上面的这两部分 ,这两行则是spring boot自动化配置的核心。

@Import:导入类,在实际开发过程中,如果你定义一个类并为这个类添加了应有的配置,那这个类就一定能够被扫描到,然后在注入吗?答案是否定的,我们并不能确定创建的类一定被到的使用,但是@Import则可以替我们保证,由它导入的实体类可以被调用。

添加这个注解主要为了导入AutoConfigurationImportSelector.class,为了确保这个类,能够被调用通过注解进行注入,那么由此可以看出,这个类在实现自动化中发挥着一个怎样的作用了!!!

看一下这个类实现的具体流程

前提我们先了解以下一些其他的信息,在进行类中代码的讲解

AutoConfigurationImportSelector.class

1:AnnotationMetadata是用来访问指定类上的注解,获取元数据

AnnotationMetadata 存在两个实现类分别为 StandardAnnotationMetadata与 AnnotationMetadataReadingVisitorStandardAnnotationMetadata主要使用 Java 反射原理获取元数据,而 AnnotationMetadataReadingVisitor 使用 ASM 框架获取元数据。

类中的方法一:获取数据,如果有则要自动开启自动配置如果没有数据则调用

getAutoConfigurationEntry(annotationMetadata);方法

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

	private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

	private static final String[] NO_IMPORTS = {};

	private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);

	private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

	private ConfigurableListableBeanFactory beanFactory;

	private Environment environment;

	private ClassLoader beanClassLoader;

	private ResourceLoader resourceLoader;

	private ConfigurationClassFilter configurationClassFilter;

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

如果方法一中没有元数据,则需要调用此方法 getAutoConfigurationEntry

方法二: getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

这个方法里面就是通过调用getCandidateConfigurations 来获取候选的 Bean,并将其存为一个集合,最后经过去重,校验等一系列操作之后,被封装成 AutoConfigurationEntry 对象返回。

方法三: getCandidateConfigurations()

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = new ArrayList<>(
				SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
		ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
		Assert.notEmpty(configurations,
				"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

通过方法三调用方法四:

getSpringFactoriesLoaderFactoryClass()

	protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}

自动化具体流程:

项目启动时,会从spring.factories获取EnableAutoConfiguration中的数据值➡获取自动配置数据,会将这些数据导入到容器中,自动配置类就会生效,搭配自动化环境➡jar包autoconfigure存放着自动配置,他会将配置和组件全都被添加到容器中➡当组件和配置全都被搭配好,就可以直接使用自动化无需在进行手动配置了

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想睡醒的梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值