安装一个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
与 AnnotationMetadataReadingVisitor
。StandardAnnotationMetadata
主要使用 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存放着自动配置,他会将配置和组件全都被添加到容器中➡当组件和配置全都被搭配好,就可以直接使用自动化无需在进行手动配置了