前言
spring注解开发的组件注册可以完全使用注解来做到,舍弃了传统的xml配置文件,取而代之的是使用配置类来设置配置信息
@Configuration
此注解标注在类上,表名该类为配置类,配置类的作用和配置文件一样。
@Bean
该注解可标注在方法上,容器初始化时将调用该方法,并将该方法的返回值注入到容器中,组件的名字默认为方法名。
如果显式的指定了组件名称,方法名将被忽略
@AliasFor("name")
String[] value() default {};
用于设置要被注入的组件的名字,作用同name属性
2.
boolean autowireCandidate() default true;
用于设置该组件是否会被自动装配到其他组件中
3.
String initMethod() default "";
用于设置该组件的初始化方法
@ComponentScan
该注解用于指定要扫描的包,容器将会注入被扫描的包中的被标记的组件。
该注解可以在一个配置类上多次标注
@AliasFor("basePackages")
String[] value() default {};
用于指定要扫描的包名,作用同basePackages属性
`Class<?>[] basePackageClasses() default {};
将会扫描指定类所在的包
boolean useDefaultFilters() default true;
指示是否使用默认的过滤器,在使用默认过滤器的情况下,将会把被扫描的包中的所有被@Controller、@Service、@Repository、@Component标注的类注入到容器
在该注解内部,定义了一个内部注解@Filter,用于匹配要注入的组件。
@interface Filter {
//FilterType是一个枚举类型。用于指定匹配模式,默认是按注解匹配
FilterType type() default FilterType.ANNOTATION;
//用于指定将要被当作过滤器的类
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
/*此属性为tpye属性服务。若type属性被设置为AspectJ
此值应为AspectJ表达式;若type属性被设置为REGEX,此值应为
正则表达式*/
String[] pattern() default {};
}
type属性有5种取值,其中最为常用的有
- FilterType.ANNOTATION, 按注解匹配
- FilterType.ASSIGNABLE_TYPE,按类类型匹配
- FilterType.CUSTOM, 自定义匹配模式,需要自己写一个实现了TypeFilter接口的类
下面将分别演示
假如我们现在需要将所有被@MyAnnotation标注的组件注入容器,可以这样来写@Filter注解:
@Filter(classes=MyAnnotation.class, type=FilterType.ANNOTATION)
假如我们将所有MyClass类型及其子类都注入容器,可以这样写:
@Filter(type=FilterType.ASSIGNABLE_TYPE, classes=MyClass.class)
Filter[] includeFilters() default {};
指定过滤器,这些过滤器匹配到的组件将被注册进容器。与此属性作用相反的属性为Filter[] excludeFilters() default {};
@Scope
用于设置组件的作用域
@AliasFor("scopeName")
String value() default "";
该属性的取值有4个
- singleton 单实例,默认值,默认情况下在容器生成时立即注入
- prototype 多实例 默认情况下在从容器中获取该组件时,才会注入该组件到容器,且每次获取都会创建一个新对象注入容器(懒加载)
- request 一次请求创建一个实例(不常用)
- session 一个session创建一个实例(不常用)
@Lazy
boolean value() default true;
用于设置组件是否是懒加载的,默认是是的
@Conditional
此注解在springBoot中应用十分广泛,用于有条件的注入组件
它可以标注在类上,也可标注在方法上
@Conditional注解仅有一个属性Class<? extends Condition>[] value();
用于指定条件判断类
我们创建一个实现了Condition接口的类,重写其中的boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
方法
对于被此注解标注的每一个将要注入的组件,都会使用此方法判断是否满足条件
@Import
标注在类上,它仅有一个属性:
/**
* {@link Configuration @Configuration},
* {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar},
* or regular component classes to import.
*/
Class<?>[] value();
注释表明:既可以传入一个配置类,也可传入一个实现了ImportSelector接口的类,或者是实现了ImportBeanDefinitionRegistrar接口的类,或者是直接传入要注入的组件的class
其中最为常用的是传入一个实现了ImportSelector接口的类,这个接口有个String[] selectImports(AnnotationMetadata importingClassMetadata);
此方法的返回值便是要导入的组件的全类名
FactoryBean
首先我们可以创建一个实现了FactoryBean接口的类,充当bean工厂
该接口有如下方法:
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
第一个getObject方法的返回值将会被注册进容器,第二个getObjectType方法的返回值为该工厂注册的bean的class,第三个方法控制注入的bean是单例还是多例。默认是单例的。
我们将工厂bean注入进容器后,再用该工厂bean的id获取组件,获取的组件并不是该工厂bean本身,而是该工厂bean生产的组件。如果想要获得工厂bean本身,需要在id前面加上&。
示例:
工厂bean定义:
public class ColorFactory implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
return new Color("red");
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
工厂bean所注入的组件的定义:
public class Color {
public String type;
public Color(String type) {
this.type = type;
}
}
将工厂bean注入容器:
@Bean
public ColorFactory colorFactory(){
return new ColorFactory();
}
测试代码:
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println(
context.getBean("colorFactory").getClass().getName());
System.out.println(
context.getBean("&colorFactory").getClass().getName());
}
测试结果: