Spring 模式注解装配
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
模式注解是一种用于声明在应用中扮演“组件”角色的注解。如 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 |
装配方式
-
<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
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>
-
@ComponentScan
方式
public class SpringConfiguration {
...
}
自定义模式注解
-
@Component
"派生性"
/**
* 一级 {@link Repository @Repository}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
String value() default "";
}
* @Component
* @Repository
* @FirstLevelRepository
-
@Component
"层次性"
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
String value() default "";
}
* @Component
* @Repository
* @FirstLevelRepository
* @SecondLevelRepository
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 | 服务熔断模块 |
实现方式
注解驱动方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends
WebMvcConfigurationSupport {
...
}
注解驱动方式
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
...
}
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
/**
* {@inheritDoc}
* @return {@link ProxyCachingConfiguration} or {@code
AspectJCacheConfiguration} for
* {@code PROXY} and {@code ASPECTJ} values of {@link
EnableCaching#mode()}, respectively
*/
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {
AutoProxyRegistrar.class.getName(),ProxyCachingConfiguration.class.getName() };
case ASPECTJ:
return new String[] {
AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME };
default:
}
}
自定义 @Enable
模块
基于注解驱动实现 @EnableHelloWorld
public class HelloWorldConfiguration {
@Bean
public String helloWorld(){
return "hello world 2018";
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldConfiguration.class) //基于注解
public @interface EnableHelloWorld {
}
基于接口驱动实现
public class HelloWorldConfiguration {
@Bean
public String helloWorld(){
return "hello world 2018";
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldImportSelector.class)//基于接口 弹性
public @interface EnableHelloWorld {
}
public class HelloWorldImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{HelloWorldConfiguration.class.getName()};
}
}
Spring 条件装配
从 Spring Framework 3.1 开始,允许在 Bean 装配时增加前置条件判断
条件注解举例
Spring注解 | 场景说明 | 起始版本 |
---|---|---|
@Profile | 配置化条件装配 | 3.1 |
@Conditional | 编程条件装配 | 4.0 |
实现方式
- 配置方式-
@Profile
- 编程方式-
@Conditional
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
/**
* The classes that must be present. Since this annotation is parsed by loading class
* bytecode, it is safe to specify classes here that may ultimately not be on the
* classpath, only if this annotation is directly on the affected component and
* <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
* use this annotation as a meta-annotation, only use the {@link #name} attribute.
* @return the classes that must be present
*/
Class<?>[] value() default {};
/**
* The classes names that must be present.
* @return the class names that must be present.
*/
String[] name() default {};
}
自定义条件装配
基于配置方式实现-@Profile
计算服务,多整数求和 sum
- 引导类
@ComponentScan(basePackages = "com.imooc.diveinspringboot.service")
public class CalculateServiceBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootstrap.class)
.web(WebApplicationType.NONE).profiles("java8")
.run(args);
CalculateService calculateService = context.getBean(CalculateService.class);
System.out.println("sum :"+calculateService.sum(1,2,3,4,5,6,7,8,9,10));
context.close();
}
}
- 计算接口
public interface CalculateService {
/**
* 多个整数求和
* @param values v
* @return sum
*/
Integer sum(Integer...values);
}
- @Profile("Java7") : for 循环
@Profile("java7")
@Service
public class Java7CalculateService implements CalculateService {
@Override
public Integer sum(Integer... values) {
System.out.println("java7 sum");
int sum = 0;
for(Integer v :values){
sum+=v;
}
return sum;
}
}
- @Profile("Java8") : Lambda
@Profile("java8")
@Service
public class Java8CalculateService implements CalculateService {
@Override
public Integer sum(Integer... values) {
System.out.println("java8 sum");
return Stream.of(values).reduce(0,Integer::sum);
}
}
基于编程方式实现-@ConditionalOnSystemProperty
通过判断系统配置值来装载Bean
- 引导类
public class SystemPropertyConditionBootstrap {
@ConditionOnSystemProperty(name = "user.name",value = "zed")
@Bean
public String helloWorld(){
return "hello zed!";
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(SystemPropertyConditionBootstrap.class).web(WebApplicationType.NONE).run(args);
String helloWorld = context.getBean("helloWorld",String.class);
System.out.println(helloWorld);
context.close();
}
}
- Condition 注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionOnSystemProperty {
/**
* 名称
* @return name
*/
String name();
/**
* 值
* @return value
*/
String value();
}
- 条件实现类
implements Condition
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String,Object> attributes = metadata.getAnnotationAttributes(ConditionOnSystemProperty.class.getName());
String propertyName = String.valueOf(attributes.get("name"));
String propertyValue = String.valueOf(attributes.get("value"));
String javaPropertyValue = System.getProperty(propertyName);
return javaPropertyValue.equals(propertyValue);
}
}
Spring Boot 自动装配
底层装配技术
- Spring 模式注解装配
- Spring
@Enable
模块装配 - Spring 条件装配
- Spring 工厂加载机制
- 实现类:
SpringFactoriesLoader
- 配置资源:
META-INF/spring.factories
- 实现类:
自动装配举例
参考 `META-INF/spring.factories`
实现方法
1.激活自动装配-@EnableAutoConfiguration
2.实现自动装配-XXXAutoConfiguration
3.配置自动装配实现-META-INF/spring.factories
自定义自动装配
HelloWorldAutoConfiguration
* 条件判断:user.name == "zed"
* 模式注解: @Configuration
* @Enable
模块:@EnableHelloWorld
-> HelloWorldImportSelector
->HelloWorldConfiguration
->helloWorld
网友评论