生命在应用中扮演组件角色的注解
@Component @Service @Configuration
不同注解代表了组件在springApplication中的角色。
SecondLevelRepository继承自元注解@Component,他也具备其特性。被@SecondLevelRepository标注的注解,也是ComponentScan的扫描和加载的对象。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
String value() default "";
}
/**
* 层次性:一级的注解可以用来标注二级注解
* 派生性: 每层注解集成上级注解的特性
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
String value() default "";
}
Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。
@EnableWebMvc、@EnableAutoConfigruation
自定义enable模块
配置类用来生成HelloWoldBean
@Configuration
public class HelloWorldConfiguration {
@Bean
public String helloWorld() { // 方法名即 Bean 名称
return "Hello,World 2018";
}
}
启动类用来获取容器中的bean这里使用了@EnableHelloWorld注解来自定义容器中的bean
@EnableHelloWorld
public class EnableHelloWorldBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println("helloworld Bean:"+helloWorld);
//close context
context.close();
}
}
自定义EnableHelloWorld注解
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//@Import(HelloWorldImportSelector.class)
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
注意:这里有两种方式@Import,第一种直接引入HelloWorldConfiguration类,这样只能创建该配置生成的bean
第二种方式,通过ImportSelector的方法,动态选择注入的bean对象,更加的灵活
@Configuration
public class HelloWorldImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//在选择其中可以选择不同的Helloworld实现方式
return new String[]{HelloWorldConfiguration.class.getName()};
}
}
在装配Bean前做判断是否加载bean
profile用法有一定局限性,Contitional是更普遍的用法
@Service
@Profile("java7")
public class Java7CalculateServiceImpl implements CalculateService {
@Override
public Integer sum(Integer... values) {
System.out.println("java7 implement");
return Stream.of(values).reduce(0,Integer::sum);
}
}
@Service
@Profile("java8")
public class Java8CalculateServiceImpl implements CalculateService {
@Override
public Integer sum(Integer... values) {
System.out.println("java8 implement");
return Stream.of(values).reduce(0,Integer::sum);
}
}
@ComponentScan(basePackages = "com.kouryoushine.springbootlearingexample.service")
public class CalculateServiceBootStrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootStrap.class)
.web(WebApplicationType.NONE)
.profiles("java7")
.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));
//close context
context.close();
}
}
自定义一个拥有条件装配的注解ConditionalOnSystemProperty,包含了2个属性
/**
* java系统属性判断
*/
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnSystemPropertyCondition.class})
public @interface ConditionalOnSystemProperty {
String name(); //系统参数名
String value(); //参数值
}
定义条件判断的class,OnSystemPropertyCondition
/**
* 系统属性条件判断
*/
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取注解ConditionalOnSystemProperty的属性和值
Map annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
String name = String.valueOf( annotationAttributes.get("name"));
String value = String.valueOf( annotationAttributes.get("value"));
String javaPropertyValue = System.getProperty(name);
//判断注解传入的value值是否等于系统参数
return value.equals(javaPropertyValue);
}
}
测试
判断系统用户名是否是Administrator,如果是则注入helloworldBean,否则不注入
/**
* 系统属性判断
*/
public class SystemPropertyConditionBootstrap {
//条件满足是才会装载helloWorldbean
@Bean
@ConditionalOnSystemProperty(name = "user.name",value = "Administrator")
public String helloWorld(){
return "Hello WOrld Admin";
}
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);
//close context
context.close();
}
}
SpringBoot准守约定大于配置原则,使用了下面几种底层装配技术
在启动类里加入@EnableAutoConfiguration注解,就会通过Meta-INF的spring.factories的文件扫描对应的类
@EnableAutoConfiguration
public class EnableAutoConfigurationBootStrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootStrap.class)
.web(WebApplicationType.NONE)
.run(args);
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println("helloworld Bean:"+helloWorld);
//close context
context.close();
}
}
META-INF/spring.factories文件内容,指定自动装配对象
# 将HelloWorldAutoConfiguration类指定为自动装配的对象
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.kouryoushine.springbootlearingexample.configuration.HelloWorldAutoConfiguration
这里三个注解融合了本文的全部内容
/**
* HelloWorld自动装配
*/
@Configuration //注解模式装配
@EnableHelloWorld //enable模块装配
@ConditionalOnSystemProperty(name = "user.name",value = "Administrator") //条件装配
public class HelloWorldAutoConfiguration {
//@EnableHelloWorld 避免了模块化的开发
}
springboot的自动装配是通过springframework 的手动装配模式一步一步构建的。