Spring Boot之从Spring Framework装配掌握SpringBoot自动装配
Spring Framework模式注解
模式注解是一种用于声明在应用中扮演“组件”角色的注解。如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的模式注解。
模式注解(角色注解)
Spring Framework 注解 | 场景说明 |
---|---|
@Component | 通用组件模式注解 |
@Controller | Web 控制器模式注解 |
@Service | 服务模式注解 |
@Repository | 数据仓储模式注解 |
@Configuration | 配置类模式注解 |
在Spring中进行装配 方式
<?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
http://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 或者其派生 Annotation 标记的类(Class),将它们注册为 Spring Bean -->
<context:component-scan base-package="com.imooc.dive.in.spring.boot" />
</beans>
在Spring中基于Java注解配置方式
@ComponentScan(basePackages = "com.imooc.dive.in.spring.boot")
public class SpringConfiguration {
...
}
自定义模式注解
上面这些都是spring自带的注解装配。那么如何自定义注解装配呢?
利用@Component模式注解具有“派生性”和“层次性”,我们能够自定义创建Bean注解
第一步:自定义SpringBean注解
//@Component 派生性
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
String value() default "";
}
//@Component 层次性
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
String value() default "";
}
第二步:将注解作用在自定义Bean上。
// @SecondLevelRepository(value = "myFirstLevelRepository") 这个注解和下面的注解作用相同,都是将类交给spring容器管理,这个注解体现@Component的层次性
@FirstLevelRepository (value = "myFirstLevelRepository")
public class MyFirstLevelRepository {
}
第三步:测试是否可以spring容器中获取到自定义Bean
import com.example.springboot01.repository.MyFirstLevelRepository;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan; @ComponentScan(basePackages = "com.example.springboot01.repository") //basePackages的值就是注解@FirstLevelRepository所注解类的包名
public class RepositoryBootstrap { public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(RepositoryBootstrap.class)
.web(WebApplicationType.NONE)
.run(args); MyFirstLevelRepository myFirstLevelRepository = context.getBean("myFirstLevelRepository",MyFirstLevelRepository.class);
System.out.println("======"+myFirstLevelRepository);
//关闭上下文
context.close();
}
} //或者
@SpringBootApplication
public class SpringBoot01Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringBoot01Application.class, args);
MyFirstLevelRepository myFirstLevelRepository = run.getBean("myFirstLevelRepository", MyFirstLevelRepository.class);
System.out.println("myFirstLevelRepository" + myFirstLevelRepository.toString());
run.close();
}
}
Spring @Enable 模块注解
Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。
@Enable 注解模块举例
框架实现 | @Enable 注解模块 | 激活模块 |
---|---|---|
Spring Framework | @EnableWebMvc | Web MVC 模块 |
@EnableTransactionManagement | 事务管理模块 | |
@EnableCaching | Caching 模块 | |
@EnableMBeanExport | JMX 模块 | |
@EnableAsync | 异步处理模块 | |
@EnableWebFlux | Web Flux 模块 | |
@EnableAspectJAutoProxy AspectJ | 代理模块 | |
Spring Boot | @EnableAutoConfiguration | 自动装配模块 |
@EnableManagementContext | Actuator 管理模块 | |
@EnableConfigurationProperties | 配置属性绑定模块 | |
@EnableOAuth2Sso | OAuth2 单点登录模块 | |
Spring Cloud
|
@EnableEurekaServer
|
Eureka服务器模块 |
@EnableConfigServer
|
配置服务器模块
|
|
@EnableFeignClients
|
Feign客户端模块
|
|
@EnableZuulProxy
|
服务网关 Zuul 模块
|
|
@EnableCircuitBreaker
|
服务熔断模块
|
@Enable实现方式
- 注解驱动方式
- 接口编程方式
自定义注解驱动方式
第一步:实现自定义注解@EnableHelloWorld
/**
* 激活 HelloWorld 模块
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class) //指定激活的类
//@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}
第二步:创建MyBeanConfig配置类
/**
* HelloWorld 配置
* 要激活的类
*/
public class HelloWorldConfiguration { //激活的Bean
@Bean
public String helloWorld() { // 方法名即 Bean 名称
return "Hello,World 2020";
} }
第三步:在应用中测试使用@EnableMyBean
/**
* {@link EnableHelloWorld} 引导类
*/
@EnableHelloWorld //自定义的注解中,会自动激活标志的类
public class EnableHelloWorldBootstrap { public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
.web(WebApplicationType.NONE)
.run(args); // helloWorld Bean 是否存在
String helloWorld =
context.getBean("helloWorld", String.class); System.out.println("helloWorld Bean : " + helloWorld); // 关闭上下文
context.close();
}
} //或者
@SpringBootApplication
@EnableHelloWorld
public class SpringBoot01Application { public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(SpringBoot01Application.class)
.web(WebApplicationType.NONE)
.run(args);
String bean = context.getBean("helloWorld", String.class);
System.out.println("bean: " + bean);
context.close();
}
}
自定义@Enable接口编程方式
第一步:实现自定义注解@EnableMyBean
/**
* 激活 HelloWorld 模块
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}
PS:注意@Import(HelloWorldConfigSelector.class)导入的类和@Enable注解驱动导入的不一样,这里导入的是一个实现了ImportSelector接口的类
/**
* HelloWorld {@link ImportSelector} 实现
* ImportSelector接口是至spring中导入外部配置的核心接口,
* 在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在
* 主要作用是收集需要导入的配置类
*/
public class HelloWorldImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
importingClassMetadata.getAnnotationTypes().forEach(System.out::println);
return new String[]{MyBeanConfig.class.getName()};
}
}
PS:在HelloWorldConfigSelector类中我们可以自定义复杂的逻辑,这里我们仅仅简单返回MyBeanConfig配置类。
第二步:创建MyBeanConfig配置类
/**
* HelloWorld 配置
* 要激活的类
*/
public class HelloWorldConfiguration {
//激活的Bean
@Bean
public String helloWorld() { // 方法名即 Bean 名称
return "Hello,World 2020";
}
}
第三步:测试使用@EnableMyBean
/**
* {@link EnableHelloWorld} 引导类
*/
@EnableHelloWorld //自定义的注解中,会自动激活标志的类
public class EnableHelloWorldBootstrap { public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
.web(WebApplicationType.NONE)
.run(args); // helloWorld Bean 是否存在
String helloWorld =
context.getBean("helloWorld", String.class); System.out.println("helloWorld Bean : " + helloWorld); // 关闭上下文
context.close();
}
}
PS:其实@Enable接口的实现方式和@Enable注解实现方式是基本一样的,只不过多了一个步骤,方便我们更灵活地进行编写逻辑。
Spring Framework条件装配
从 Spring Framework 3.1 开始,允许在 Bean 装配时增加前置条件判断
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Profile | 配置化条件装配 | 3.1 |
@Conditional | 编程条件装配 | 4.0 |
自定义@Profile配置化条件装配
第一步:自定义创建某服务不同的@Profile实现类
/**
* 计算服务
*/
public interface CalculateService { /**
* 从多个整数 sum 求和
* @param values 多个整数
* @return sum 累加值
*/
Integer sum(Integer... values);
}
/**
* Java 7 for 循环实现 {@link CalculateService}
*/
@Profile("Java7")
@Service
public class Java7CalculateService implements CalculateService { @Override
public Integer sum(Integer... values) {
System.out.println("Java 7 for 循环实现 ");
int sum = 0;
for (int i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
} public static void main(String[] args) {
CalculateService calculateService = new Java7CalculateService();
System.out.println(calculateService.sum(1,2,3,4,5,6,7,8,9,10));
} }
/**
* Java 8 Lambda 实现 {@link CalculateService}
*/
@Profile("Java8")
@Service
public class Java8CalculateService implements CalculateService { @Override
public Integer sum(Integer... values) {
System.out.println("Java 8 Lambda 实现");
int sum = Stream.of(values).reduce(0, Integer::sum);
return sum;
} public static void main(String[] args) {
CalculateService calculateService = new Java8CalculateService();
System.out.println(calculateService.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
}
}
第二步:在构建Spring容器指定配置
/**
* {@link CalculateService} 引导类*/
@SpringBootApplication(scanBasePackages = "com.example.springboot01.service") //将类放入容器中
public class CalculateServiceBootstrap { public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootstrap.class)
.web(WebApplicationType.NONE)
.profiles("Java8") //指定那个实现
.run(args); // CalculateService Bean 是否存在
CalculateService calculateService = context.getBean(CalculateService.class); System.out.println("calculateService.sum(1...10) : " +
calculateService.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // 关闭上下文
context.close();
}
}
自定义@Conditional 编程条件装配
第一步:创建一个自定义注解
/**
* Java 系统属性 条件判断
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty { /**
* Java 系统属性名称
* @return
*/
String name(); /**
* Java 系统属性值
* @return
*/
String value();
}
PS:注意@Conditional注解,将会找到MyOnConditionProperty类的matches方法进行条件验证
第二步:创建该注解的条件验证类,该类实现Condition接口
/**
* 系统属性条件判断
*/
public class OnSystemPropertyCondition implements Condition { @Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//注解传过来的所有值
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
//获取name的值
String propertyName = String.valueOf(attributes.get("name"));
//获取value的值
String propertyValue = String.valueOf(attributes.get("value"));
//根据name值获取对应name的系统值
String javaPropertyValue = System.getProperty(propertyName);
//判断value值是否与name属性对应的系统值相同
return propertyValue.equals(javaPropertyValue);
}
}
第三步:在Spring应用中应用条件装配
/**
* 系统属性条件引导类
*/
public class ConditionalOnSystemPropertyBootstrap { @Bean
@ConditionalOnSystemProperty(name = "java.runtime.name", value = "Java(TM) SE Runtime Environment aa") //对应系统java.runtime.name属性的值不是value中的,多了aa,所以装配失败
public String helloWorld() {
return "Hello,World";
} public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(ConditionalOnSystemPropertyBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
// 通过名称和类型获取 helloWorld Bean
String helloWorld = context.getBean("helloWorld", String.class); System.out.println("helloWorld Bean : " + helloWorld); // 关闭上下文
context.close();
}
}
PS:本例自定义的MyConditionOnPropertyAnnotion在应用中装配的时候可以指定name和value值,该值将会在实现了Condition借口的matches进行条件验证,如果验证通过,则在Spring容器中装配该Bean,反之则不装配。
SpringBoot 自动装配
在 Spring Boot 场景下,基于约定大于配置的原则,实现 Spring 组件自动装配的目的。其中底层使用了一系列的Spring Framework手动装配的方法来构成Spring Boot自动装配。
自定义SpringBoot自动装配
- 激活自动装配 - @EnableAutoConfiguration
- 实现自动装配 - XXXAutoConfiguration
- 配置自动装配实现 - META-INF/spring.factories
第一步:实现自动装配 - XXXAutoConfiguration
/**
* HelloWorld 自动装配
*/
@Configuration // Spring 模式注解装配
@EnableHelloWorld // Spring @Enable 注解装配
@ConditionalOnSystemProperty(name = "java.runtime.name", value = "Java(TM) SE Runtime Environment") // 条件装配
public class HelloWorldAutoConfiguration {
}
第二步:配置自动装配实现 - META-INF/spring.factories
放到resources文件夹中
# 自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.springboot01.configuration.HelloWorldAutoConfiguration
第三步:激活自动装配- @EnableAutoConfiguration
/**
* {@link EnableAutoConfiguration} 引导类
*/
@EnableAutoConfiguration
public class EnableAutoConfigurationBootstrap { public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class)
.web(WebApplicationType.NONE)
.run(args); // helloWorld Bean 是否存在
String helloWorld =
context.getBean("helloWorld", String.class); System.out.println("helloWorld Bean : " + helloWorld); // 关闭上下文
context.close(); }
}
本章总结
本章我们主要了解了Spring Framework的模式注解装配,@Enable装配和条件装配。对于SpringBoot的自动装配我们仅仅做了一下演示,遵循SpringBoot装配的三个步骤,我们就可以运行SpringBoot的自动装配。但是对于SpringBoot为什么要遵循这三个步骤?自动装配的原理?我们不知所以然,所以下一章节我们仍然以SpringBoot的自动装配为主题,对SpringBoot的底层源码做剖析。
感谢:https://www.cnblogs.com/jimisun/p/10070123.html
Spring Boot之从Spring Framework装配掌握SpringBoot自动装配的更多相关文章
- 一步步从Spring Framework装配掌握SpringBoot自动装配
目录 Spring Framework模式注解 Spring Framework@Enable模块装配 Spring Framework条件装配 SpringBoot 自动装配 本章总结 Spring ...
- SpringBoot自动装配的原理
1.SpringApplication.run(AppConfig.class,args);执行流程中有refreshContext(context);这句话. 2.refreshContext(co ...
- [Spring Boot]什么是Spring Boot
<Spring Boot是什么> Spring Boot不是一个框架 是一种用来轻松创建具有最小或零配置的独立应用程序的方式 用来开发基于Spring的应用,但只需非常少的配置. 它提供了 ...
- spring boot 打包方式 spring boot 整合mybaits REST services
<build> <sourceDirectory>src/main/java</sourceDirectory> <plugins> <plugi ...
- 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的
系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...
- spring boot(五):spring data jpa的使用
在上篇文章springboot(二):web综合开发中简单介绍了一下spring data jpa的基础性使用,这篇文章将更加全面的介绍spring data jpa 常见用法以及注意事项 使用spr ...
- 使用 Spring Boot 快速构建 Spring 框架应用--转
原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/ Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2 ...
- 使用 Spring Boot 快速构建 Spring 框架应用,PropertyPlaceholderConfigurer
Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2002 年发布以来,Spring 框架已经成为企业应用开发领域非常流行的基础框架.有大量的企业应用基于 Spring 框架来开发.S ...
随机推荐
- MySQL 分库分表 dble简单使用
一.运行环境 Host Name IP DB Mod data0 172.16.100.170 mysql data1 172.16.100.171 mysql data2 172.16.10 ...
- linux学习8 运维基本功-Linux获取命令使用帮助详解
一.Linux基础知识 1.人机交互界面: a.GUI b.CLI:[login@hostname workdir]# COMMAND 2.命令知识 通用格式:# COMMAND OPTIONS A ...
- 每个开发人员必须知道PDB文件知识
大多数开发人员都意识到PDB文件有助于您进行调试,但仅此而已.如果你不知道PDB文件是怎么回事,不要觉得很糟糕,因为虽然有文档在那里,但它分散在周围,而且大部分是为编译器和调试器编写器准备的.虽然编写 ...
- Redis存储Hash
结构: 1.存取操作: (1)单个存取: (2)一次存储多个,单个取出: 一次取出多个·: (3)取出全部的键和值: 2.删除: (1)删除单个键值对: (2)删除所有键值对: 3.增加数值: 4.减 ...
- 开源项目 12 ServiceStack.OrmLite
using ServiceStack; using ServiceStack.DataAnnotations; using ServiceStack.OrmLite; using ServiceSta ...
- SIGIR2018 Paper Abstract Reading Notes (1)
1.A Click Sequence Model for Web Search(日志分析) 更好的理解用户行为对于推动信息检索系统来说是非常重要的.已有的研究工作仅仅关注于建模和预测一次交互行为,例如 ...
- git-中文乱码
Windows系统的Git默认是不支持中文显示的,需要进行一系列的设置才能避免乱码的出现,下面总结如何配置Git使其支持中文显示. Git bash options UTF-8编码配置 1.首先进入g ...
- 【AE软件】视频添加字幕
1.导入视频 2.将视频拖入大屏幕 3.在下面点击右键——新建——文本 4.文字属性设置
- Android自动化测试--monkey总结
什么是 Monkey Monkey 是一个 Android 自动化测试小工具.主要用于Android 的压力测试, 主要目的就是为了测试app 是否会Crash. Monkey 特点 顾名思义,Mon ...
- [转]OpenGL图形渲染管线、VBO、VAO、EBO概念及用例
直接给出原文链接吧 1.OpenGL图形渲染管线.VBO.VAO.EBO概念及用例 2.OpenGL中glVertex.显示列表(glCallList).顶点数组(Vertex array).VBO及 ...