Spring 模式注解装配
Spring @Enable 模块装配
注解驱动方式 eg:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
接口编程方式 eg:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
}
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
public String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
case PROXY:
return this.getProxyImports();
case ASPECTJ:
return this.getAspectJImports();
default:
return null;
}
}
}
Spring 条件装配
@Profile
,根据不同环境进行装配@Conditional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
Spring 工厂加载机制
项目结构如下
添加核心Bean=>HelloWorld,只有一个hello方法用于测试输出结果
@Slf4j
public class HelloWorld {
public void hello(){
log.info("hello world 2019!");
}
}
添加HelloWorldConfiguration用于注册HelloWorld
@Slf4j
public class HelloWorldConfiguration {
@Bean
public HelloWorld hello(){
log.info("Load HelloWorld");
return new HelloWorld();
}
}
添加HelloWorldImportSelector实现ImportSelector,通过接口编程方式实现@Enable功能
@Slf4j
public class HelloWorldImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
log.info("annotationMetadata.getAnnotationTypes():{}",annotationMetadata.getAnnotationTypes());
// 此处可写分支条件,根据指定条件选择性注册某些类 或者返回null
return new String[]{HelloWorldConfiguration.class.getName()};
}
}
添加@EnableHelloWorld用于控制是否装配HelloWorld
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//@Import(HelloWorldConfiguration.class) // 基于注解驱动实现Sprig @Enable模块
@Import(HelloWorldImportSelector.class) // 基于接口驱动实现Spring @Enable模块
public @interface EnableHelloWorld {
}
注:如果直接使用@Import(HelloWorldConfiguration.class)注解方式实现,则不需要HelloWorldImportSelector类,但是注解方式无法添加分支判断,只能指定加载指定类
@Configuration // 模式注解,声明是一个bean
@ConditionalOnSystemProperty(name = "user.name", value = "Administrator") // 正确的条件装配
//@ConditionalOnSystemProperty(name = "user.name", value = "lxt") // 错误的条件装配
@EnableHelloWorld // Spring @Enable 模块装配
public class HelloWorldAutoConfiguration {
}
在resources下添加META-INF/spring.factories配置文件,用于启动是通过工厂机制(SpringFactoriesLoader)加载
# 自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.lxt.springboot.autoconfigure.configuration.HelloWorldAutoConfiguration
添加测试类HelloWorldService
@Component
public class HelloWorldService {
@Autowired
private HelloWorld helloWorld;
@PostConstruct
public void init(){
helloWorld.hello();
}
}
启动项目,控制台输出如下,测试开启情况成功
2019-11-24 21:25:02.299 INFO 13880 --- [ main] c.l.s.a.a.HelloWorldImportSelector : annotationMetadata.getAnnotationTypes():[com.lxt.springboot.autoconfigure.condition.ConditionalOnSystemProperty, com.lxt.springboot.autoconfigure.annotation.EnableHelloWorld]
2019-11-24 21:25:02.710 INFO 13880 --- [ main] c.l.s.a.c.HelloWorldConfiguration : Load HelloWorld
2019-11-24 21:25:02.712 INFO 13880 --- [ main] c.l.s.autoconfigure.entity.HelloWorld : hello world 2019!
去掉@EnableHelloWorld 注解或者条件注解修改为ConditionalOnSystemProperty(name = “user.name”, value = “lxt”),分别重启,控制台输出如下,测试关闭情况成功
***************************
APPLICATION FAILED TO START
***************************
Description:
Field helloWorld in com.lxt.springboot.autoconfigure.service.HelloWorldService required a bean of type 'com.lxt.springboot.autoconfigure.entity.HelloWorld' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.lxt.springboot.autoconfigure.entity.HelloWorld' in your configuration.