写在前面  

  spring boot能够根据依赖的jar包自动配置spring boot的应用,例如: 如果类路径中存在DispatcherServlet类,就会自动配置springMvc相关的Bean。spring boot的自动装配来源于spring的装配,功能也是随时spring的不断升级不断完善的,spring boot正是在spring的基础上实现的自动装配。

spring模式注解装配

模式注解介绍

   模式注解是应用程序中用来标注组件的注解,例如:@Repository是spring框架中用来标注数据访问对象(DAO)的注解。@Component是用来标注被spring管理的通用的组件,@Component标注的类都可以被spring容器扫描到。并且任何标注@Component元注解的的注解也能被spring扫描到,比如@Service

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}

下面是spring中常用的模式注解

spring注解 使用场景 起始版本
@Repository 数据仓储模式注解 2.0
@Component 通用组件模式注解 2.5
@Service 服务模式注解 2.5
@Controller Web 控制器模式注解 2.5
@Configuration 配置类模式注解 3.0

装配方式

​ spring中通过配置扫描的包 ,就能扫描到注解的组件,有两种配置的方式:

XML配置

通过context:component-scan标签的base-package属性,配置需要扫描的包

<context:component-scan base-package="com.laoliangcode.service,com.laoliangcode.dao"/>

注解方式装配

@ComponentScan(basePackages = "com.laoliangcode.service,com.laoliangcode.dao")

自定义模式注解

​ 可以通过在自定义注解上加上元注解的方式,自定义模式注解。例如:@UserRepository注解上加上元注解@Repository,这样@UserRepository也是模式注解了。这是由于注解具有派生性的特点,@UserRepository派生至@Repository,@Repository派生至@Component

@Repository
public @interface UserRepository {
String value() default "";
}

spring @Enable模块装配

​ spring3.1开始支持@Enable模块装配,所谓模块是指,把具有相同功能的组件组合在一起,引入到项目中。比如@EnableWebMvc注解,就是把spring MVC相关的配置引入到项目中,而不需要其他配置,方便使用spring MVC。这种装配方式是通过@Import注解引入其他配置类来实现的,@EnableWebMvc通过引入DelegatingWebMvcConfiguration配置类,实现spring MVC的自动配置。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

​ 引入的配置类有两种实现形式,一种是直接使用模式注解@Configuration的类,另一种是实现ImportSelector接口的selectImports方法,来引入配置类。

注解方式

​ @EnableWebMvc就是这种实现方式。
​ 下面列举User模块的装配来具体说明实现的方式。可以看出EnableUserConfig是通过直接导入UserConfiguration来装配User模块的。

UserConfiguration配置类

  @Configuration
public class UserConfiguration {
@Bean
public UserService userService(UserDao userDao){
return new UserService(userDao);
@Bean
public UserDao userDao() {
return new UserDao();
}
}

EnableUserConfig注解

  @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfiguration.class)
public @interface EnableUserConfig {
}

使用启动类

  @EnableUserConfig
public class EnableUserConfigBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(EnableUserConfigBootstrap.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println("EnableUserConfigBootstrap.main" + userService.findBId(1));
context.close();
}
}

ImportSelector接口方式

​ spring中的EnableCaching就是这种实现方式。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
}

​ 下面列举User模块的装配来具体说明实现的方式。这种方式是通过UserConfigurationSelector来引入User的配置类UserConfiguration

UserConfigurationSelector类用来导入UserConfiguration配置

public class UserConfigurationSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {UserConfiguration.class.getName()};
}
}

EnableUserSelector注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfigurationSelector.class)
public @interface EnableUserSelector {
}

使用启动类

@EnableUserSelector
public class EnableUserSelectorBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(EnableUserSelectorBootstrap.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println("EnableUserSelectorBootstrap.main" + userService.findBId(1));
context.close();
}
}

spring条件装配

​ spring3.1开始,spring引入了@Profile注解,可以根据环境Environment的不同引入不同的配置。spring4.0开始,Conditional注解可以更灵活的根据不同条件引入不同的配置。

@Profile注解方式的条件装配

​ 使用User模块的不能dao装配来说明@Profile的条件装配。

UserProfileConfiguration配置

@Configuration
public class UserProfileConfiguration {
@Bean
public UserServiceForProfile userServiceForProfile(IUserDao userDao) {
return new UserServiceForProfile(userDao);
}
@Bean
@Profile("mysql")
public IUserDao userMysqlDao() {
return new UserMysqlDao();
}
@Bean
@Profile("oracle")
public IUserDao userOracleDao() {
return new UserOracleDao();
}
}

Environment激活使用

通过context.getEnvironment().setActiveProfiles("oracle");的方式,来激活不同的Profile

public class ProfileBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
context.register(UserProfileConfiguration.class);
context.getEnvironment().setActiveProfiles("oracle");
context.refresh();
UserServiceForProfile userService = context.getBean("userServiceForProfile",
UserServiceForProfile.class);
System.out.println("ProfileBootstrap.main" + userService.findBId(1));
context.close();
}
}

@Conditional注解方式的条件装配

​ @Conditional注解方式,通过引入实现Condition接口的类,来判断条件是否成立,从而确定是否引入某个组件。这个类是通过实现matches方法来判断条件是否成立。spring4.0开始,由于引入了@Conditional注解,Profile也是通过@Conditional来实现的。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}

​ spring boot中大量使用了@Conditional注解的方式,来自动装配不同的组件。@ConditionalOnClass用来表示类路径存在某些类时加载;@ConditionalOnMissingBean用来判断某些类的实例不存在时加载;ConditionalOnWebApplication用来判断某种应用类型时加载。例如webmvc的自动加载配置WebMvcAutoConfiguration:

    @Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}

​ 下面的例子是根据系统变量的值来决定是否装配UserDao

OnSystemPropertyCondition 实现Condition接口的matches方法,用来判断是否符合条件

  public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
String propertyName = String.valueOf(annotationAttributes.get("name"));
String propertyValue = String.valueOf(annotationAttributes.get("value"));
String systemPropertyValue = System.getProperty(propertyName);
return propertyValue.equals(systemPropertyValue);
}
}

ConditionalOnSystemProperty注解

  @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
String name();
String value();
}

启动类

  public class ConditionalOnSystemPropertyBootstrap {
@ConditionalOnSystemProperty(name = "user.name", value = "Administrator")
@Bean
public UserDao userDao() {
return new UserDao();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(ConditionalOnSystemPropertyBootstrap.class);
UserDao userDao = context.getBean("userDao", UserDao.class);
System.out.println("ConditionalOnSystemPropertyBootstrap.main" + userDao.findBId(1));
context.close();
}
}

如果value指定错误,就会报错:

  Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userDao' available

spring boot自动装配

​ spring boot的自动装配结合了上面介绍的spring模式注解、@Enable模块装配和条件装配。另外,spring boot自身还使用了工厂加载机制,用SpringFactoriesLoader来装载配置类。

实现方法

  1. 实现自动装配的类
  2. META-INF/spring.factories文件中配置第一步中的类
  3. @EnableAutoConfiguration注解激活配置
    下面以User模块的自动装配为例,来介绍具体的实现步骤

实现装配类UserAutoConfiguration

这里用到了前面介绍的@Enable模块装配和条件装配

@EnableUserSelector
@ConditionalOnSystemProperty(name = "user.name", value = "Administrator")
public class UserAutoConfiguration {
}

META-INF/spring.factories文件中添加配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.laoliangcode.configuration.UserAutoConfiguration

SpringBoot核心特性之组件自动装配的更多相关文章

  1. springboot 2.0 自定义redis自动装配

    首先创建maven项目 pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xm ...

  2. Spring Boot之从Spring Framework装配掌握SpringBoot自动装配

    Spring Framework模式注解 模式注解是一种用于声明在应用中扮演“组件”角色的注解.如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的 ...

  3. 一步步从Spring Framework装配掌握SpringBoot自动装配

    目录 Spring Framework模式注解 Spring Framework@Enable模块装配 Spring Framework条件装配 SpringBoot 自动装配 本章总结 Spring ...

  4. 深入理解SpringBoot之自动装配

    SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提.其实它并不那么神秘,我在这之前已经写过最基本的实现了,大家可以参考这篇文章.这次主要的议题是,来看看它是怎么样实现的,我们透过源代码 ...

  5. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  6. Spring Boot 自动装配(二)

    目录 目录 前言 1.起源 2.Spring Boot 自动装配实现 2.1.@EnableAutoConfiguration 实现 2.1.1. 获取默认包扫描路径 2.1.2.获取自动装配的组件 ...

  7. Spring(二)-生命周期 + 自动装配(xml) +自动装配(注解)

    1.生命周期 **Spring容器的 bean **的生命周期: 1.1 默认生命周期 1.1.1 生命周期 调用构造方法,创建实例对象: set方法,给实例对象赋值: init 初始化方法 初始化对 ...

  8. 从源码中理解Spring Boot自动装配原理

    个人博客:槿苏的知识铺 一.什么是自动装配 SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot在启动时会扫描外部引用jar包中的META-INF/spring.factori ...

  9. 20、自动装配-@Autowired&@Qualifier&@Primary

    20.自动装配-@Autowired&@Qualifier&@Primary 自动装配:Spring 利用依赖注入(DI),完成对IOC容器中各个依赖关系赋值 20.1 @Autowi ...

随机推荐

  1. C++输入输出流加速器,关闭同步流,ios::sync_with_stdio(false)和 cin.tie(0)

    leetcode练习时,总会发现运行时间短的代码都会有类似: static int x=[](){ std::ios::sync_with_stdio(false); cin.tie(NULL); ; ...

  2. MySQL 给已存在的数据表 增加字段和注释

    MySQL 给已存在的数据表 增加字段和注释 问题描述 在开发一个系统的过程中,经常会遇到随着系统服务功能的扩展,或者服务之间的关联,需要适当的修改原有的表结构,比如,增加一些必要的字段. 示例:在已 ...

  3. Web jsp开发学习——数据库的另一种连接方式(配置静态数据库连接池)

    1.导包   2.找到sever里的sever.xml,配置静态数据库连接池 <Context docBase="bookstore" path="/booksto ...

  4. LCTF (easyeasy-200)

    首先安装,看看app是什么样的. 有点奇怪,没有点击确定的按钮.然后拖到JEB反编译. 要求输入的字符串的长度要在35-39之间(包括边界值),然后会调用Format().form函数.如下图. 可以 ...

  5. markdown-博客编辑

    1. 快捷键 2. 基本语法 2.1 字体设置斜体.粗体.删除线 2.2 分级标题 2.3 链接 2.4 分割线 2.5 代码块 2.6 引用 2.7 列表 2.8 表格 3. 常用技巧 3.1 换行 ...

  6. 关于.Net Core+Angular+Ueditor富文本编辑器的使用方式

    博客:https://www.cnblogs.com/24klr/ 资料:https://www.jianshu.com/p/0b21a1324d47 GitHub:https://github.co ...

  7. python 爬虫 urllib模块 发起post请求

    urllib模块发起的POST请求 案例:爬取百度翻译的翻译结果 1.通过浏览器捉包工具,找到POST请求的url 针对ajax页面请求的所对应url获取,需要用到浏览器的捉包工具.查看百度翻译针对某 ...

  8. lua编译器和ide

    这里有一个网址,上面记录了大部分流行的LUA开发工具,包括IDE和Editor. http://www.wowwiki.com/Lua_editors 一.Eclipse LDT 1.语法高亮,自动提 ...

  9. [Python3] 041 文件 持久化

    目录 文件 持久化 1. pickle 1.1 例子1 1.2 例子2 1.3 注意 2. shelve 2.1 举例 2.2 特性 2.3 强制写回 2.4 使用 with 管理上下文环境 文件 持 ...

  10. Java第七周课堂示例总结

    一.super();调用基类构造方法 代码: class Grandparent{ public Grandparent(){ System.out.println("GrandParent ...