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自动装配

  1. 激活自动装配 - @EnableAutoConfiguration
  2. 实现自动装配 - XXXAutoConfiguration
  3. 配置自动装配实现 - 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自动装配的更多相关文章

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

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

  2. SpringBoot自动装配的原理

    1.SpringApplication.run(AppConfig.class,args);执行流程中有refreshContext(context);这句话. 2.refreshContext(co ...

  3. [Spring Boot]什么是Spring Boot

    <Spring Boot是什么> Spring Boot不是一个框架 是一种用来轻松创建具有最小或零配置的独立应用程序的方式 用来开发基于Spring的应用,但只需非常少的配置. 它提供了 ...

  4. spring boot 打包方式 spring boot 整合mybaits REST services

    <build> <sourceDirectory>src/main/java</sourceDirectory> <plugins> <plugi ...

  5. 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)

    前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...

  6. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  7. spring boot(五):spring data jpa的使用

    在上篇文章springboot(二):web综合开发中简单介绍了一下spring data jpa的基础性使用,这篇文章将更加全面的介绍spring data jpa 常见用法以及注意事项 使用spr ...

  8. 使用 Spring Boot 快速构建 Spring 框架应用--转

    原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/ Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2 ...

  9. 使用 Spring Boot 快速构建 Spring 框架应用,PropertyPlaceholderConfigurer

    Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2002 年发布以来,Spring 框架已经成为企业应用开发领域非常流行的基础框架.有大量的企业应用基于 Spring 框架来开发.S ...

随机推荐

  1. MySQL 分库分表 dble简单使用

    一.运行环境 Host Name IP DB Mod data0 172.16.100.170 mysql   data1 172.16.100.171 mysql   data2 172.16.10 ...

  2. linux学习8 运维基本功-Linux获取命令使用帮助详解

    一.Linux基础知识 1.人机交互界面: a.GUI b.CLI:[login@hostname workdir]# COMMAND 2.命令知识 通用格式:# COMMAND  OPTIONS A ...

  3. 每个开发人员必须知道PDB文件知识

    大多数开发人员都意识到PDB文件有助于您进行调试,但仅此而已.如果你不知道PDB文件是怎么回事,不要觉得很糟糕,因为虽然有文档在那里,但它分散在周围,而且大部分是为编译器和调试器编写器准备的.虽然编写 ...

  4. Redis存储Hash

    结构: 1.存取操作: (1)单个存取: (2)一次存储多个,单个取出: 一次取出多个·: (3)取出全部的键和值: 2.删除: (1)删除单个键值对: (2)删除所有键值对: 3.增加数值: 4.减 ...

  5. 开源项目 12 ServiceStack.OrmLite

    using ServiceStack; using ServiceStack.DataAnnotations; using ServiceStack.OrmLite; using ServiceSta ...

  6. SIGIR2018 Paper Abstract Reading Notes (1)

    1.A Click Sequence Model for Web Search(日志分析) 更好的理解用户行为对于推动信息检索系统来说是非常重要的.已有的研究工作仅仅关注于建模和预测一次交互行为,例如 ...

  7. git-中文乱码

    Windows系统的Git默认是不支持中文显示的,需要进行一系列的设置才能避免乱码的出现,下面总结如何配置Git使其支持中文显示. Git bash options UTF-8编码配置 1.首先进入g ...

  8. 【AE软件】视频添加字幕

    1.导入视频 2.将视频拖入大屏幕 3.在下面点击右键——新建——文本 4.文字属性设置

  9. Android自动化测试--monkey总结

    什么是 Monkey Monkey 是一个 Android 自动化测试小工具.主要用于Android 的压力测试, 主要目的就是为了测试app 是否会Crash. Monkey 特点 顾名思义,Mon ...

  10. [转]OpenGL图形渲染管线、VBO、VAO、EBO概念及用例

    直接给出原文链接吧 1.OpenGL图形渲染管线.VBO.VAO.EBO概念及用例 2.OpenGL中glVertex.显示列表(glCallList).顶点数组(Vertex array).VBO及 ...