[TOC]html
模式注解是一种用于声明在应用中扮演“组件”角色的注解。如 Spring Framework 中的 @Repository 标注在任何类上 ,用 于扮演仓储角色的模式注解。java
模式注解(角色注解)web
Spring Framework 注解 | 场景说明 |
---|---|
@Component | 通用组件模式注解 |
@Controller | Web 控制器模式注解 |
@Service | 服务模式注解 |
@Repository | 数据仓储模式注解 |
@Configuration | 配置类模式注解 |
在Spring中进行装配context:component-scan 方式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 { ... }
@Component 模式注解具备“派生性”和“层次性”,咱们可以自定义建立Bean注解缓存
第一步:自定义SpringBean注解springboot
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface MyServiceAnnotation { String value() default ""; }
第二步:将注解做用在自定义Bean上框架
@MyServiceAnnotation(value = "testBean") public class TestBean { }
第三步:测试是否能够从Spring容器中获取到自定义Bean异步
@SpringBootApplication public class Main { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(Main.class, args); TestBean testBean = run.getBean("testBean", TestBean.class); System.out.println("testBean" + testBean.toString()); run.close(); } }
Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具有相同领域的功能组件集合, 组合所造成一个独立的单元。好比 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。ide
框架实现 | @Enable 注解模块 | 激活模块 |
---|---|---|
Spring Framework | @EnableWebMvc | Web MVC 模块 |
Spring Framework | @EnableTransactionManagement | 事务管理模块 |
Spring Framework | @EnableCaching | Caching 模块 |
Spring Framework | @EnableMBeanExport | JMX 模块 |
Spring Framework | @EnableAsync | 异步处理模块 |
Spring Framework | @EnableWebFlux | Web Flux 模块 |
Spring Framework | @EnableAspectJAutoProxy AspectJ | 代理模块 |
Spring Boot | @EnableAutoConfiguration | 自动装配模块 |
Spring Boot | @EnableManagementContext | Actuator 管理模块 |
Spring Boot | @EnableConfigurationProperties | 配置属性绑定模块 |
Spring Boot | @EnableOAuth2Sso | OAuth2 单点登陆模块 |
...... |
第一步:实现自定义注解@EnableMyBean
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(MyBeanConfig.class) public @interface EnableMyBean { }
PS:注意@Import(MyBeanConfig.class),将导入MyBeanConfig配置类的相关Bean
第二步:建立MyBeanConfig配置类
@Configuration public class MyBeanConfig { @Bean(name = "hello") public String hello() { return "word"; } }
第三步:在应用中测试使用@EnableMyBean
@SpringBootApplication(scanBasePackages = "com.jimisun.learnspringboot.three") @EnableMyBean public class Main { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(Main.class) .web(WebApplicationType.NONE) .run(args); String bean = context.getBean("hello", String.class); context.close(); } }
第一步:实现自定义注解@EnableMyBean
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(MyBeanConfigSelector.class) public @interface EnableMyBean { }
PS:注意@Import(MyBeanConfigSelector.class)导入的类和@Enable注解驱动导入的不同,这里导入的是一个实现了ImportSelector接口的类
public class MyBeanConfigSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{new MyBeanConfig().getClass().getName()}; } }
PS:在MyBeanConfigSelector类中咱们能够自定义复杂的逻辑,这里咱们仅仅简单返回MyBeanConfig配置类。
第三步:建立MyBeanConfig配置类
@Configuration public class MyBeanConfig { @Bean public String hello() { return "word"; } }
第四步:在应用中测试使用@EnableMyBean
@SpringBootApplication(scanBasePackages = "com.jimisun.learnspringboot.four") @EnableMyBean public class Main { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(Main.class) .web(WebApplicationType.NONE) .run(args); String bean = context.getBean("hello", String.class); context.close(); } }
PS:其实@Enable接口的实现方式和@Enable注解实现方式是基本同样的,只不过多了一个步骤,方便咱们更灵活地进行编写逻辑。
从 Spring Framework 3.1 开始,容许在 Bean 装配时增长前置条件判断
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Profile | 配置化条件装配 | 3.1 |
@Conditional | 编程条件装配 | 4.0 |
第一步:自定义建立某服务不一样的@Profile实现类
public interface UserService { void println(); }
@Service @Profile("vip") public class VipUserservice implements UserService { @Override public void println() { System.out.println("I am VIP User"); } }
@Service @Profile("common") public class CommonUserservice implements UserService { @Override public void println() { System.out.println("I am Common User"); } }
第二步:在构建Spring容器指定配置
@ComponentScan(basePackages = "com.jimisun.learnspringboot.two") public class Main { public static void main(String[] args) { ConfigurableApplicationContext run = new SpringApplicationBuilder(Main.class). web(WebApplicationType.NONE). profiles("vip"). run(args); UserService bean = run.getBean(UserService.class); bean.println(); run.close(); } }
第一步:建立一个自定义注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional({MyOnConditionProperty.class}) public @interface MyConditionOnPropertyAnnotion { String prefix() default ""; }
PS:注意@Conditional注解,将会找到MyOnConditionProperty类的matches方法进行条件验证
第二步:建立该注解的条件验证类,该类实现Condition接口
public class MyOnConditionProperty implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Map<String, Object> annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(MyConditionOnPropertyAnnotion.class.getName()); String prefix = String.valueOf(annotationAttributes.get("prefix")); return prefix.equals("pass"); } }
第三步:在Spring应用中应用条件装配
@SpringBootApplication public class Main { @Bean(name = "hello") @MyConditionOnPropertyAnnotion(prefix = "pass") public String hello() { return "word"; } public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(Main.class) .web(WebApplicationType.NONE) .run(args); String bean = context.getBean("hello", String.class); context.close(); } }
PS:本例自定义的MyConditionOnPropertyAnnotion在应用中装配的时候能够指定prefix值,该值将会在实现了Condition借口的matches进行条件验证,若是验证经过,则在Spring容器中装配该Bean,反之则不装配。
在 Spring Boot 场景下,基于约定大于配置的原则,实现 Spring 组件自动装配的目的。其中底层使用了一系列的Spring Framework手动装配的方法来构成Spring Boot自动装配。
第一步 :激活自动装配 - @EnableAutoConfiguration
@EnableAutoConfiguration public class Main { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(Main.class) .web(WebApplicationType.NONE) .run(args); String bean = context.getBean("hello", String.class); context.close(); } }
第二步:实现自动装配 - XXXAutoConfiguration
@Configuration @EnableMyBean public class HelloWordAutoConfiguration { }
PS:这里使用了上面咱们建立的@EnableMyBean,这个注解会注入一个名为“hello"的Bean
第三步:配置自动装配实现 - META-INF/spring.factories
在ClassPath目录下建立META-INF文件夹再建立spring.factories文件
#配置本身的自动装配Bean org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.jimisun.learnspringboot.five.HelloWordAutoConfiguration
最后:运行测试第一步中的Main方法,看是否能获取到名为“hello”的Bean
本章咱们主要了解了Spring Framework的模式注解装配,@Enable装配和条件装配。对于SpringBoot的自动装配咱们仅仅作了一下演示,遵循SpringBoot装配的三个步骤,咱们就能够运行SpringBoot的自动装配。可是对于SpringBoot为何要遵循这三个步骤?自动装配的原理?咱们不知因此然,因此下一章节咱们仍然以SpringBoot的自动装配为主题,对SpringBoot的底层源码作剖析。
该教程所属Java工程师之SpringBoot系列教程,本系列相关博文目录 Java工程师之SpringBoot系列教程前言&目录