SpringBoot自动注入原理初解与实现

前言:一直对SpringBoot的自动注入感兴趣,特意查了一下并进行了实现.

参考:https://blog.csdn.net/zxc123e/article/details/80222967(绝大部分是照抄了此博文,某些地方进行了改动)

https://www.cnblogs.com/duanxz/p/4520571.html

https://blog.csdn.net/gottst0113/article/details/80978966

https://www.cnblogs.com/duanxz/p/7493276.html

 

目录

第一章 实现自动装配的注解

第二章 EnableAutoConfiguration讲解

2.1 SpringFactoriesLoader

第三章 实例

3.1 自动配置类

3.1.1 pom.xml的配置

3.1.2 项目目录结构如下

3.1.3 Hello.java

3.1.4 HelloProperties.java

3.1.5 HelloAutoConfiguration.java

3.1.6 spring.factories

3.1.7 项目打包

3.2 应用类

3.2.1 pom.xml

3.2.2 主类

3.2.3 application.properties配置

3.3 进行测试 


第一章 实现自动装配的注解

首先Spring Boot项目中都会如下启动类:

@SpringBootApplication
public class TestAutoConfigApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestAutoConfigApplication.class, args);
	}

}

 从上面代码可以看出,注解@SpringBootApplicationSpringApplication.run()方法是最为重要的部分。这里主要来看看@SpringBootApplication注解部分。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...
}

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

@Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration,相当于把该类作为spring的xml配置文件中的<beans>
@EnableAutoConfiguration(实现自动装配的注解)
@ComponentScan(将标识了需要装配的类自动装配到spring的bean容器中)

如果在启动类使用这个三个注解,整个SpringBoot应用依然可以与之前的启动类功能一样。但每次写这3个比较啰嗦,所以写一个@SpringBootApplication方便点。

 

第二章 EnableAutoConfiguration讲解

既然我们要讲自动装配,是要把EnableAutoConfiguration说一下.

打开其源代码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//@Import注解是为了把某个类注入到IOC容器中,这样就可以进行自动装配啥的,也可以通过getBean获取.
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

可以看到其将AutoConfigurationImportSelector.class导入了容器,借助AutoConfigurationImportSelector@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器(注意是Configuration配置)。

打开AutoConfigurationImportSelector的源码,可以看到通过 SpringFactoriesLoader.loadFactoryNames()
把 XXX.jar/META-INF/spring.factories中每一个xxxAutoConfiguration文件都加载到容器中.

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		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;
	}

2.1 SpringFactoriesLoader

SpringFactoriesLoader属于Spring框架私有的一种扩展方案(类似于Java的SPI方案java.util.ServiceLoader),其主要功能就是从指定的配置文件META-INF/spring-factories加载配置,而spring-factories是一个典型的java properties文件,只不过Key和Value都是Java类型的完整类名,比如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration

在@EnableAutoConfiguration场景中,SpringFactoriesLoader更多提供了一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfig.EnableAutoConfiguration作为查找的Key,获得对应的一组@Configuration类。

SpringFactoriesLoader是一个被final修饰的类,类中定义的静态属性定义了其加载资源的路径public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories",此外还有三个静态方法:

loadFactories:加载指定的factoryClass并进行实例化。
loadFactoryNames:加载指定的factoryClass的名称集合。
instantiateFactory:对指定的factoryClass进行实例化。
 

public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
		Assert.notNull(factoryClass, "'factoryClass' must not be null");
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
		if (logger.isTraceEnabled()) {
			logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
		}
		List<T> result = new ArrayList<>(factoryNames.size());
		for (String factoryName : factoryNames) {
			result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
		}
		AnnotationAwareOrderComparator.sort(result);
		return result;
	}

loadFactories方法首先获取类加载器,然后调用loadFactoryNames方法获取所有的指定资源的名称集合、接着调用instantiateFactory方法实例化这些资源类并将其添加到result集合中。最后调用AnnotationAwareOrderComparator.sort方法进行集合的排序。

第三章 实例

3.1 自动配置类

 新建maven项目,pom.xml的配置如下.

3.1.1 pom.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>NewTestAutoConfig</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.1.3.RELEASE</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

3.1.2 项目目录结构如下

3.1.3 Hello.java

package com.example.newtestautoconfig;

public class Hello {
    private String msg;

    public String sayHello() {
        return "hello " + msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

3.1.4 HelloProperties.java

package com.example.newtestautoconfig;

import org.springframework.boot.context.properties.ConfigurationProperties;


@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
    private static final String MSG = "world";

    private String msg = MSG ;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

}

3.1.5 HelloAutoConfiguration.java

@Configuration
//EnableConfigurationProperties注解。该注解是用来开启对@ConfigurationProperties注解
//配置Bean的支持,提供一种方便的方式来将带有@ConfigurationProperties注解的类
//注入为Spring容器的Bean,也就是@EnableConfigurationProperties注解
//告诉Spring Boot 能支持@ConfigurationProperties
//更多信息 查看https://www.cnblogs.com/duanxz/p/4520571.html
@EnableConfigurationProperties(HelloProperties.class)

//判断这个类是否在classpath中存在,如果存在,才会实例化一个Bean

@ConditionalOnClass(Hello.class)

// matchIfMissing没有prefix所表示的前缀也会生效,value=enabled表示注入生效.
//更多详见 https://blog.csdn.net/gottst0113/article/details/80978966
@ConditionalOnProperty(prefix="hello", value="enabled", matchIfMissing = true)
public class HelloAutoConfiguration {
    @Autowired
    private HelloProperties helloProperties;

    @Bean
    @ConditionalOnMissingBean(Hello.class)//容器中如果没有Hello这个类,那么自动配置这个Hello
    public Hello hello() {
        Hello hello = new Hello();
        hello.setMsg(helloProperties.getMsg());
        return hello;
    }
}

3.1.6 spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.newtestautoconfig.HelloAutoConfiguration

3.1.7 项目打包

最后使用maven install命令将项目打包到本地

 

3.2 应用类

新建SpringBoot项目

3.2.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>NewTestAutoConfig</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.1.3.RELEASE</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

3.2.2 主类

@SpringBootApplication
@RestController

public class TestAutoConfigApplication {


	@Autowired
	private Hello hello;

	@RequestMapping("/")
	public String index() {
		return hello.sayHello();
	}

	public static void main(String[] args) {
		SpringApplication.run(TestAutoConfigApplication.class, args);
	}

}

3.2.3 application.properties配置

hello.msg=zhangsan

3.3 进行测试 

成功!

 

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值