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
模式注解是一種用于聲明在應(yīng)用中扮演“組件”角色的注解车吹。如 Spring Framework 中的 @Repository 標(biāo)注在任何類上 钱贯,用 于扮演倉儲角色的模式注解搀罢。 @Component 作為一種由 Spring 容器托管的通用模式組件陶因,任何被 @Component 標(biāo)準(zhǔn)的組件均為組件掃描的候選對象。類 似地买乃,凡是被 @Component 元標(biāo)注(meta-annotated)的注解锈死,如 @Service ,當(dāng)任何組件標(biāo)注它時掸宛,也被視作組件掃 描的候選對象
模式注解舉例
Spring Framework 注解 | 場景說明 | 起始版本 |
---|---|---|
@Repository | 數(shù)據(jù)倉儲模式注解 | 2.0 |
@Component | 通用組件模式注解 | 2.5 |
@Service | 服務(wù)模式注解 | 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">
<!-- 激活注解驅(qū)動特性 --> <context:annotation-config />
<!-- 找尋被 @Component 或者其派生 Annotation 標(biāo)記的類(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 模塊驅(qū)動“。所謂“模塊”是指具備相同領(lǐng)域的功能組件集合唧瘾, 組合所形成一個獨立 的單元措译。比如 Web MVC 模塊、AspectJ代理模塊饰序、Caching(緩存)模塊领虹、JMX(Java 管 理擴展)模塊、Async(異步處 理)模塊等求豫。
@Enable
注解模塊舉例
框架實現(xiàn) | @Enable 注解模塊 | 激活模塊 |
---|---|---|
Spring Framework | @EnableWebMvc | Web MVC 模塊 |
@EnableTransactionManagement | 事務(wù)管理模塊 | |
@EnableCaching | Caching 模塊 | |
@EnableMBeanExport | JMX 模塊 | |
@EnableAsync | 異步處理模塊 | |
@EnableWebFlux | Web Flux 模塊 | |
@EnableAspectJAutoProxy | AspectJ 代理模塊 | |
Spring Boot | @EnableAutoConfiguration | 自動裝配模塊 |
@EnableManagementContext | Actuator 管理模塊 | |
@EnableConfigurationProperties | 配置屬性綁定模塊 | |
@EnableOAuth2Sso | OAuth2 單點登錄模塊 | |
Spring Cloud | @EnableEurekaServer | Eureka服務(wù)器模塊 |
@EnableConfigServer | 配置服務(wù)器模塊 | |
@EnableFeignClients | Feign客戶端模塊 | |
@EnableZuulProxy | 服務(wù)網(wǎng)關(guān) Zuul 模塊 | |
@EnableCircuitBreaker | 服務(wù)熔斷模塊 |
實現(xiàn)方式
注解驅(qū)動方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends
WebMvcConfigurationSupport {
...
}
注解驅(qū)動方式
@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
模塊
基于注解驅(qū)動實現(xiàn) @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 {
}
基于接口驅(qū)動實現(xiàn)
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 |
實現(xiàn)方式
- 配置方式-
@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 {};
}
自定義條件裝配
基于配置方式實現(xiàn)-@Profile
計算服務(wù),多整數(shù)求和 sum
- 引導(dǎo)類
@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 {
/**
* 多個整數(shù)求和
* @param values v
* @return sum
*/
Integer sum(Integer...values);
}
- @Profile("Java7") : for 循環(huán)
@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);
}
}
基于編程方式實現(xiàn)-@ConditionalOnSystemProperty
通過判斷系統(tǒng)配置值來裝載Bean
- 引導(dǎo)類
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();
}
- 條件實現(xiàn)類
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 自動裝配
底層裝配技術(shù)
- Spring 模式注解裝配
- Spring
@Enable
模塊裝配 - Spring 條件裝配
- Spring 工廠加載機制
- 實現(xiàn)類:
SpringFactoriesLoader
- 配置資源:
META-INF/spring.factories
- 實現(xiàn)類:
自動裝配舉例
參考 `META-INF/spring.factories`
實現(xiàn)方法
1.激活自動裝配-@EnableAutoConfiguration
2.實現(xiàn)自動裝配-XXXAutoConfiguration
3.配置自動裝配實現(xiàn)-META-INF/spring.factories
自定義自動裝配
HelloWorldAutoConfiguration
* 條件判斷:user.name == "zed"
* 模式注解: @Configuration
* @Enable
模塊:@EnableHelloWorld
-> HelloWorldImportSelector
->HelloWorldConfiguration
->helloWorld