
Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。
- 定义:具备相同领域的功能组件集合,组合所形成的一个独立的单元
框架实现 | @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 单点登录模块 | |
SpringCloud | @EnableEurekaServer |
Eureka服务器模块 |
@EnableConfigServer |
配置服务器模块 | |
@EnableFeignClients |
Feign客户端模块 | |
@EnableZuulProxy |
服务网关 Zuul 模块 | |
@EnableCircuitBreaker |
服务熔断模块 |
手动装配实现原理,以@EnableWebMvc
为例
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
该注解中的关键是使用了@Import
注解,@Import
是这样的。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
java doc 给出这样一段注释:
Indicates one or more {@link Configuration @Configuration} classes to import.
大概意思就是:指示要导入的一个或多个{@link Configuration@Configuration}类。
可以大概的理解为向SpringIOC容器中注入一个或者多个配置类,就像我们下面这样
@Configuration
public class XConfigure {
@Bean
public xxx(){
return new Xxx();
}
}
自定义@EnableXXX
模块
基于注解驱动实现
- 创建一个需要被装载的类
public class HelloWorld {
public HelloWorld(){
System.out.println("hello world");
}
}
- 创建一个配置类,装载HelloWorld.
public class HelloWorldConfig {
@Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
- 自定义模块驱动注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({HelloWorldConfig.class})
public @interface EnableHelloWorld {
}
- 测试,在启动类/配置类上写
@EnableHelloWorld
装载该组件,启动SpringBoo项目,控制台打印helloworld,说明自定义注解生效,HelloWorld类被装载至SpringIOC容器中。
image.png
接口编程方式
- 新建配置类,并实现
ImportSelector
接口
public class HelloWorldSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{HelloWorld.class.getName()};
}
}
- 修改
@EnableHelloWorld
注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({HelloWorldSelector.class})
public @interface EnableHelloWorld {
}
- 启动容器,控制台打印HelloWorld,说明接口生效,基于注解驱动实现
HelloWorldImportSelector
--->HelloWorldConfiguration
--->HelloWorld
这样通过HelloWorldImportSelector间接的进行装配更加的灵活
image.png
条件装配
从Spring Framework3.1开始,允许Bean装配时增加前置条件判断
配置方式-@Profile
编程方式-@Condifional
@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 {};
}
自定义条件装配
eg:实现一个方法,java 7使用for循环的形式实现累加,java 8使用Lambda的形式实现累加。
基于配置方式实现-@Profile
- 接口:
public interface CalculateService {
/**
* 从多个整数sum求和
* @param values 多个整数
* @return sum累加值
*/
Integer sum(Integer ...values);
}
- java7实现
@Profile("Java7")
@Service
public class Java7CalculateServiceImpl implements CalculateService {
@Override
public Integer sum(Integer... values) {
System.out.println("Java7 for 循环实现{@link CalculateService}");
int sum=0;
for (Integer value : values) {
sum += value;
}
return sum;
}
}
- java8实现
@Profile("Java8")
@Service
public class Java8CalculateServiceImpl implements CalculateService {
@Override
public Integer sum(Integer... values) {
System.out.println("Java8 Lambda 循环实现{@link CalculateService}");
return Stream.of(values).reduce(0,Integer::sum);
}
}
-
启动类
只扫描service包~
@SpringBootApplication(scanBasePackages = "org.ywb.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("CalculateService.sum(1...10):"+calculateService.sum(1,2,3,4,5,6,7,8,9,10));
//关闭上下文
context.close();
}
}
基于编程方式实现
场景:只有name的值符合要求才返回相应的Bean
- 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionOnSystemProperty {
/**
* Java 系统属性名称
* @return
*/
String name();
/**
* Java 系统属性名称
* @return
*/
String value();
}
- 创建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"));
return "happy".equals(propertyName);
}
}
- 启动类
public class ConditionOnSystemPropertyBootstrap {
@Bean
@ConditionOnSystemProperty(name="happy",value = "balabala") // 只有name的值等于happy的时候,该“hello,world:-)”才会被装载
public String helloWorld(){
return "hello,world :-)";
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(ConditionOnSystemPropertyBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println(helloWorld);
//关闭上下文
context.close();
}
}
网友评论