Spring注解驱动开发04(给容器中注册组件的方式)

时间:2023-01-18 05:41:13

给容器中注册组件的方式

1. 组件注解标注 + 包扫描(适用于自己写的类)

//控制层组件
@Controller
public class PersonController {
} //业务逻辑层组件
@Service
public class PersonServic {
} //持久层组件
@Repository
public class PersonDao {
} //其他组件
@Component
public class Person {
}

包扫描(注解或者xml的方式)

1.使用注解的方式
@ComponentScan(value = "com.xxx") 2.使用xml的方式
<context:component-scan base-package="com.xxx"/>

2. @Bean(适用于第三方包里面的组件)

了解@Bean使用详情

@Bean("组件id") 默认使用方法名作为id,返回值作为组件的类型

3. @Import(快速给容器中导入一个组件)

@Import的第一种用法

  1. 直接在配置类上加上注解@Import(要加入到ioc容器中的类的类模板)
@Configuration
@ComponentScan(value = "com.atguigu",excludeFilters = {
//不扫描@controller和service注解,type默认为注解类型,可以不写
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {Myfilter.class})})
@SuppressWarnings("all")
@Import(HashMap.class) //将HashMap类加入到ioc容器中
public class MainConfig {
}

可以看到@Import注解的value时个数组,所以也可以导入多个值

注意:@Import注入的bean默认id为类的全限定名

public @interface Import {

	/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value(); } @Import(HashMap.class,TreeMap.class) //将HashMap类加入到ioc容器中
public class MainConfig {
}
  1. 编写测试类
    @Test
public void testImport(){
try(ConfigurableApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class)) {
//查看容器中的所有对象
String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
  1. 查看打印结果
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
personController
personServic
java.util.HashMap //可以看到ioc容器中已经有hashmap
java.util.TreeMap //可以看到ioc容器中已经有treemap
person
p1

@Import的第二种用法:ImportSelector方式【重点】

这种方式的前提就是一个类要实现ImportSelector接口,假如我要用这种方法,目标对象是Myclass这个类,分析具体如下:

  1. 创建Myclass类并实现ImportSelector接口
//自定义逻辑返回需要导入的组件
public class MyClass implements ImportSelector { /**
* @param importingClassMetadata 表示当前被@Import注解给标注的所有注解信息【不是重点】
* @return 就是我们实际上要导入到容器中的组件全类名【重点 】
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
"java.util.LinkedHashSet",
"java.util.ArrayList"
};
} }
  1. 在@Import注解上加入属性自定义类
@Import({HashMap.class, TreeMap.class, MyClass.class})
  1. 测试类
    @Test
public void testImport(){
try(ConfigurableApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class)) {
System.out.println(ioc);
//查看容器中的所有对象
String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
  1. 查看打印结果

    Spring注解驱动开发04(给容器中注册组件的方式)

@Import的第三种用法:ImportBeanDefinitionRegistrar方式

同样是一个接口,类似于第二种ImportSelector用法,相似度80%,只不过这种用法比较自定义化注册,具体如下:

第一步:创建Myclass2类并实现ImportBeanDefinitionRegistrar接口

public class Myclass2 implements ImportBeanDefinitionRegistrar {
//该实现方法默认为空
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { }
}

参数分析:

  • 第一个参数:annotationMetadata 和之前的ImportSelector参数一样都是表示当前被@Import注解给标注的所有注解信息
  • 第二个参数表示用于注册定义一个bean

第二步:编写代码,自定义注册bean

public class Myclass2 implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//指定bean定义信息(包括bean的类型、作用域...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class);
//注册一个bean指定bean名字(id)
beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition);
}
}

第三步:编写TestDemo 类,并标注上使用ImportBeanDefinitionRegistrar方式的Myclass2类

@Import({TestDemo2.class,Myclass.class,Myclass2.class})
public class TestDemo { @Bean
public AccountDao2 accountDao222(){
return new AccountDao2();
} }

第四步:运行结果

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
personController
personServic
java.util.HashMap
java.util.TreeMap
java.util.LinkedHashSet
java.util.ArrayList
person
p1
TestDemo4444 //可以看到已经在ioc中

4. @Import注解的三种使用方式总结

第一种用法:@Import({ 要导入的容器中的组件 } ):容器会自动注册这个组件,id默认是全类名

第二种用法:ImportSelector:返回需要导入的组件的全类名数组,springboot底层用的特别多【重点 】

第三种用法:ImportBeanDefinitionRegistrar:手动注册bean到容器

以上三种用法方式皆可混合在一个@Import中使用,特别注意第一种和第二种都是以全类名的方式注册,而第三中可自定义方式。

@Import注解本身在springboot中用的很多,特别是其中的第二种用法ImportSelector方式在springboot中使用的特别多,尤其要掌握!