1 通过@Configuration和@Bean为容器添加Bean
Spring使用@configuration注解标识配置类
@Bean注解
向容器中注册Bean,id为方法名,同时也可以使用@Bean(“person”)的方式配置方法名
使用AnnotationConfigApplicationContext可以获取容器,容器中注册的bean通过注解方式配置进去,AnnotationConfigApplicationContext的构造方法需要指定配置类的class类型,具体代码为
ApplicationContext applicatioinContext = new AnnotationConfigApplicationContext(MainConfig.class);
applicatioinContext .getBean(Person.class) 获取bean
applicatioinContext .getBeanNamesForType(Person.class)
通过Class类型获取bean的名字 返回结果为String[]
2 通过@ComponentScan完成包扫描
依旧写在有@Configuration注解的配置文件中,通过注解参数指定要扫描的包,具体示例如下:
@Configuraion
@ComponentScan(value = " com.meituan", includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.Class}),
@Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class }),
},useDefaultFilters = false)
@ComponentScan(value = " com.meituan", excludeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.Class})
})
public Class MainConfig{
}
excludeFilters = Filter[] 扫描的时候按照规则排除哪些组件
includeFilters = Filter[] 扫描的时候按照规则只包含哪些组件,但是需要将useDefaultFilters设置为false后才能生效
applicatioinContext .getBeanDefinitionNames() 能够看到bean容器中所有容器定义的名字,返回结果为String[]
在JDK1.8以后ComponentScan注解可以重复使用,同时也可以通过@ComponentScans注解指定多个扫描
3 通过TypeFilter指定过滤规则
FilterType.ANNOTATION 按照注解进行过滤
FilterType.ASSIGNABLE_TYPE 按照指定的类型进行过滤
FilterType.ASPECTJ 使用ASPECTJ表达式
FilterType.REGEX 使用正则表达式
FilterType.CUSTOM 使用自定义规则
自定义规则必须是一个TypeFilter的实现类
public class MyTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
4 通过Scope注解调整组件作用域
@Scope
prototype:多例的 ioc容器启动并不会去调用方法创建对象在容器中,而是每次获取时才会调用方法创建对象,获取几次调用几次
singleton:单例的(默认值) ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是从容器中拿
针对单实例bean,通过@lazy注解可以将其调整为懒加载方式
5 通过Conditional注解完成条件注册
可以通过Conditional注解完成条件注册
@Conditional(LinuxCondition.Class) 必须满足条件才能将bean注册进容器中,该注解既可以修饰类,也可以修饰方法。
最终的判断类需要实现Condition注解
public class LinuxCondition implements Condition {
/**
* ConditionContext,判断条件能使用的上下文环境
* AnnotatedTypeMetadata注释信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1,能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3获取当前环境
Environment environment = context.getEnvironment();
//4获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器中bean的注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
}
给容器中中注册组件的几种方式
包扫描+组件标注注解(@Component、@Service、@Controller、@Repository,添加到自己写的类上边)
2、@Bean[导入的第三方包里面的组件]
3、@Import[快速给容器中导入一个组件]
@Import({Color.class,Red.class})也能通过数组的方式导入多个组件
1、Import(类名),容器中就会自动注册这个组件,id默认是组件的全名
2、ImportSelector:返回需要导入的组件的全类名的数组
@Import(Color.class, Red.class, MyImportSelector.class)
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
//返回值就是导入到容器中组件的全类名
//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
//importingClassMetadata
//方法不要返回null值
return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
}
}
通过ImportSelector的实现类,将该类型的返回值导入到容器中
3、ImportBeanDefinitionRegistrar:手动注册bean
@Import(Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class)
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类
* 把所有添加到容器中的bean调用
* BeanDefinitionRegistry.registerBeanDefinition手工注册进来
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
if(definition && definition2){
//指定Bean定义信息,(Bean的类型)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
//注册一个bean,指定bean名
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
4、使用Spring提供的FactoryBean(工厂bean)
1、默认获取到的是工厂bean调用getObject创建的对象
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是否是单例
//true,这个bean是一个单实例bean,在容器中保存一份
//false,这个bean多实例,每次获取都会创建一个新的bean
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
最后在config类中注入此FactoryBean
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
这里我们貌似向容器中注入的是FactoryBean,但是实际上容器中注入bean的类型是我们在FactoryBean中所生成的类型
Object bean2 = applicationContext.getBean("colorFactoryBean");
如果想要获取到bean本身,需要给id前面加个&标识
Object bean4 = applicationContext.getBean("&colorFactoryBean");
System.out.println(bean4.getClass());