走向自动装配|第一章-Spring Framework 手动装配
文章目录
文章说明
Spring Framework 到 Spring Boot 怎么一步一步走向自动装配
- 第一章 - Spring Framework 手动装配
- 第二章 - @Enable 模块驱动
- 第三章 - Spring Boot 条件装配
- 第四章 - Spring Boot 自动装配
项目环境
- jdk 1.8
- Spring Boot 2.0.2.RELEASE
- github 地址:https://github.com/huajiexiewenfeng/deep-in-spring-boot
- 本章模块:autoconfigure
1.Spring 模式注解装配
定义:一种用于声明在应用中扮演 组件
角色的注解
举例:@Component、@Service、@Configuration 等
装配:<context:component-scan …> 或者 @ComponentScan
2.Stereotype Annotations 模式注解
A stereotype annotation is an annotation that is used to declare the role that a component plays within the application. For example, the
@Repository
annotation in the Spring Framework is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).
@Component
is a generic stereotype for any Spring-managed component. Any component annotated with@Component
is a candidate for component scanning. Similarly, any component annotated with an annotation that is itself meta-annotated with@Component
is also a candidate for component scanning. For example,@Service
is meta-annotated with@Component
.Core Spring provides several stereotype annotations out of the box, including but not limited to:
@Component
,@Service
,@Repository
,@Controller
,@RestController
, and@Configuration
.@Repository
,@Service
, etc. are specializations of@Component
.
模式注解是一种用于声明在应用中扮演“组件”角色的注解。如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的模式注解。
@Component 作为一种由 Spring 容器托管的通用模式组件,任何被 @Component 标准的组件均为组件扫描的候选对象。类似的,凡是被 @Component 元标注(meta-annotated)的注解,如 @Service ,当任何组件标注它时,也被视作组件扫描的候选对象。
模式注解举例:
Spring Framework 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓库模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解 | 3.0 |
3.装配方式
<context:component-scan …> 方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 激活注解驱动特性 -->
<context:annotation-config/>
<!-- 寻找被 @Component 或者其派生注解标记的类,将它们注册为 Spring Bean -->
<context:component-scan base-package="com.huajie.deepinspringboot"/>
</beans>
@ComponentScan 方式
@ComponentScan(basePackages = "com.huajie.deepinspringboot")
public class SpringConfiguration {
...
}
在 SpringBoot 场景中 @SpringBootApplication
启动类的注解已经包含了这个 @ComponentScan
注解。
4.自定义模式注解
4.1 @Component “派生性”
新建 @FirstLevelRepository 使用 @Repository 进行元标注
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
// 方法签名保持一致
String value() default "";
}
层次关系:@Component -> @Repository -> @FirstLevelRepository
测试:
新建 MyFirstLevelRepository 使用 @FirstLevelRepository 进行标注
@FirstLevelRepository("myFirstLevelRepository")
public class MyFirstLevelRepository {
}
测试引导类
@SpringBootApplication(scanBasePackages = "com.huajie.deepinspringboot.repository")
public class RepositoryBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(RepositoryBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
MyFirstLevelRepository bean = context.getBean("myFirstLevelRepository", MyFirstLevelRepository.class);
System.out.println(bean);
context.close();
}
}
执行结果:
com.huajie.deepinspringboot.repository.MyFirstLevelRepository@187eb9a8
可以看到被我们自定义注解标注的 MyFirstLevelRepository 类已经被扫描 Spring IoC 中,这就是@Component 注解的“派生性”。
4.2 @Component “层次性”
新建 @SecondLevelRepository 使用 @FirstLevelRepository 进行元标注
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
// 方法签名保持一致
String value() default "";
}
层次关系:@Component -> @Repository -> @FirstLevelRepository -> @SecondLevelRepository
新建 MySecondLevelRepository 使用 @SecondLevelRepository 进行标注
@SecondLevelRepository("mySecondLevelRepository")
public class MySecondLevelRepository {
}
测试引导类
@SpringBootApplication(scanBasePackages = "com.huajie.deepinspringboot.repository")
public class RepositoryBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(RepositoryBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
MyFirstLevelRepository bean = context.getBean("myFirstLevelRepository", MyFirstLevelRepository.class);
MySecondLevelRepository bean2 = context.getBean("mySecondLevelRepository", MySecondLevelRepository.class);
System.out.println(bean);
System.out.println(bean2);
context.close();
}
}
执行结果:
com.huajie.deepinspringboot.repository.MyFirstLevelRepository@13d186db
com.huajie.deepinspringboot.repository.MySecondLevelRepository@6f6962ba
虽然 @SecondLevelRepository 没有直接被 @Component 标注,但是 @SecondLevelRepository 和 @FirstLevelRepository 效果类似,这就是@Component 注解的“层次性”。
4.3 @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 {
...
SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
}
层次关系:@Component -> @Configuration-> @SpringBootConfiguration -> @SpringBootApplication
在 Spring Boot 场景中,@SpringBootApplication 也是模式注解。
5.参考
- 慕课网-小马哥《Spring Boot2.0深度实践之核心技术篇》