Spring组件注册就是让Spring的IOC容器去管理组件的这个bean,
SPring组件基于注解的注册方法主要有以下几种:
首先需要一个@Configuration注解的配置类,告诉Spring容器配置的入口,和xml配置文件的功能一样
一:@Bean
首先新建一个Person类,属性为String:name,Integer:age;
新建配置类,代码如下:
@Configuration//表示当前类为一个配置类
public class MainConfig01 {
@Bean
public Person person() {
return new Person("Alen", 18);
}
}
测试类如下:
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new
AnnotationConfigApplicationContext(MainConfig01.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
打印出来容器中的组件除了Spring本身自带的还有这两个: mainConfig01 person
- @Bean默认beanDefinitionName为方法名,也可以指定@Bean("Alen")
- @Bean 和xml文件配置中的<Bean>标签一致,也可以指定以下属性
2.1.默认为单例模式,scope可以指定单例还是多例,单例默认在容器创建是创建组件并放入容器,多例则在获取时创建
2.2指定init-method和destory-method,单例下Bean的生命周期交给容器管理,init-method和destory-method都会执行,多例下只 会执行destory-method
2.3.@Lazy注解,组件会在容器获取时初始化创建。
二:@ComponentScan+@Component(@Service,@Repository,@Controller)
包扫描+组件注解,@ComponentScan中可以指定要扫描的包中加注了组件注解的类
在@ComponentScan注解中,
1.默认会自动扫描以下四个注解注解的组件
/**
* Indicates whether automatic detection of classes annotated with {@code @Component}
* {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
*/
boolean useDefaultFilters() default true;
2.标签值为@Filter的两个过滤器
Filter[] excludeFilters() default {};//排除
Filter[] includeFilters() default {};//包含
值为@Filter,默认的过滤类型为注解格式,
/**
* The type of filter to use.
* <p>Default is {@link FilterType#ANNOTATION}.
* @see #classes
* @see #pattern
*/
FilterType type() default FilterType.ANNOTATION;
在Filter Type枚举类型中还有其他几个格式
public enum FilterType {
// Filter candidates marked with a given annotation.
ANNOTATION,//按照注解过滤
// Filter candidates assignable to a given type.
ASSIGNABLE_TYPE,//按照类型过滤
// Filter candidates matching a given AspectJ type pattern expression.
ASPECTJ,//使用ASPECTJ表达式
// Filter candidates matching a given regex pattern.
REGEX,//按照正则过滤
//Filter candidates using a given custom
CUSTOM//按照用户自定义
}
按照自定义的规则
{@link org.springframework.core.type.filter.TypeFilter} implementation.
我们需要去实现TypeFilter接口,举个例子,代码如下:
public class MyFliterType implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
//此处只测试是否匹配扫描的类名包含Demo
if (className.contains("Demo")) {
return true;
}
return false;
}
}
配置类如下:
@Configuration
@ComponentScan(value = "com.practice.bean")
public class MainConfig01 {
@Bean
public Person person() {
return new Person("Alen", 18);
}
}
测试类:
@Test
public void test02() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig01.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig01
controllerDemo
daoDemo
serviceDemo
person
- 1。@ComponentScan(value = "com.practice.bean", excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = { Controller.class}) }),将Controller注解的组件排除在外,controllerDemo将不会注册
- 2。@ComponentScan(value = "com.practice.bean", useDefaultFilters = false)将使用默认的过滤器开关置为false,则@Component(@Service,@Repository,@Controller)四个注解的组件将不会自动扫描注册
- 3.@ComponentScan(value = "com.practice.bean", excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = { MyFliterType.class}) }),根据自定义规则包含Demo的组件将不会被注册
includeFilters此处不再讲解,需要将useDefaultFilters = false置为false,因为默认开启会扫描Componernt四个注解。
三。@Conditional按照条件加载,满足条件则会加载
自定义一个条件,需要实现Condition类,代码如下
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;
}
return false;
}
}
此类的意思是在操作系统在Windows环境下则加载
在扫描的com.practice.bean包中加了@Component注解的某个类上加上@Conditional(value = MyCondition.class)注解
我们将启动参数改为-Dos.name=Linux,则此组件将不会再被注册。
四。@Import(value = { })导入组件
1. 直接导入
在bean的包下先建一个 MyImport类,我们将此注解@Import(value = { MyImport.class })加在我们的主配置类上,执行测试类,
可以看到,输出的组件中包含了该类的全类名(默认ID为全类名)。
2.ImportSelector:导入组件选择器,
2.1实现接口ImportSelector:
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//importingClassMetadata.getClassName()为配置类
return new String[] { "com.practice.bean.MyImport" };
}
}
配置类注解@Import(value = {MyImportSelector.class }),执行测试类,可以看到MyImport组件已注册
2.2ImportBeanDefinitionRegistrar:导入组件定义注册器
作用:实现ImportBeanDefinitionRegistrar接口,我们可以为容器注册组件。
新建ImportBeanDefinitionRegistrarTest类以做测试:
public class ImportBeanDefinitionRegistrarTest{
}
新建MyImportBeanDefinitionRegistrar类,为容器注册ImportBeanDefinitionRegistrarTest类的Bean定义信息,导入该组件。
代码如下:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(ImportBeanDefinitionRegistrarTest.class);
registry.registerBeanDefinition("importBeanDefinitionRegistrarTest", beanDefinition);
}
}
配置类注解改为@Import(value = {MyImportSelector.class,MyImportBeanDefinitionRegistrar.class }),执行测试类,可以看到importBeanDefinitionRegistrarTest组件已注册。
五。使用FactoryBean注册组件
FactoryBean实现类如下:
public class MyFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
return new Person();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
配置类修改为
@Configuration
@ComponentScan(value = "com.practice.bean")
public class MainConfig01 {
@Bean
public MyFactoryBean MyFactoryBean() {
return new MyFactoryBean();
}
}
运行测试类,可以看到MyFactoryBean已被注册。那么这个MyFactoryBean就是MyFactoryBean类吗?
我们在测试类中加上:
Object bean = applicationContext.getBean("MyFactoryBean");
System.out.println(bean);
打印出的bean为com.practice.bean.Person类,说明Person已被注册到容器中。
那么怎么获取这个MyFactoryBean类组件呢,使用&符号,源码中已给出说明。
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";
Object bean = applicationContext.getBean("&MyFactoryBean");
打印bean.getClass.Console显示class com.practice.bean.MyFactoryBean。