一、@componentScan注解
1、注册bean
//给容器中注册一个bean;类型为返回值类型,id默认是用方法名作为id
//如果@Bean("name"),则调用时是使用通过那么来获取
@Bean("person")
public Person person01(){
return new Person("李四",20);
}
2、新建配置类
//在新建类上加上注释@configura,
@Configuration//告诉spring这是一个配置类
//配置类就等于以前的配置文件
包扫描:
@ComponentScan(value = "com.atguigu",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
})
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[]
3、自定义FilterType
系统给定的类型有:
public enum FilterType {
ANNOTATION,//按照注解形式
ASSIGNABLE_TYPE,//按照给定的类型
ASPECTJ,//使用aspectj表达式:基本不会使用
REGEX,//正则表达式
CUSTOM//使用自定义规则
}
自定义规则需要实现这个接口:
@FunctionalInterface
public interface TypeFilter {
//metadataReader:读取到当前正在扫描的类的信息
// metadataReaderFactory:可以获取到其他任何类信息的
boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QjhUxwUs-1597651405808)(/…/…/…/1.png)]
自定义的类如下:
public class MyTypeFilter implements TypeFilter {
//metadataReader:读取到当前正在扫描的类的信息
// metadataReaderFactory:可以获取到其他任何类信息的
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的信息(类型/实现什么接口)
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源的信息(类路径...)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("------->"+className);
return false;
}
在配置类添加使用(返回布尔值):
@ComponentScan(value = "com.atguigu",includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
结果:返回值为false;且还没有指定过滤类型,所以扫描的是全部的,但是未添加到容器
添加简单的自定义判断后:
if(className.contains("er")){//类明含有er则添加到容器,否则不添加
return true;
}
return false;
结果:myTypeFilter并不是组件但是也包含了[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XXk3P805-1597651405813)(/…/…/…/源码截图/1597647990719.png)]
二、@Scope设置组件作用域
/**
* prototype:多实例的
* singleton:单实例的(默认值)
* request:同一次请求创建一个实例
* session:同一个session创建一个实例
*/
@Scope()
1、测试单例下
Object person = applicationContext.getBean("person");
Object person2 = applicationContext.getBean("person");
System.out.println(person==person2);
结果:
mainConfig2
person
true
2、测试多例模式下
@Scope("prototype")
结果
mainConfig2
person
false
结论:
用@scope(prototype)控制作用范围:每次获取Bean的时候会有一个新的实例
3、探究何时将bean放入容器
单例模式下:
@Scope()
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person...");
return new Person("张三",25);
}
结果:
给容器中添加Person...
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
mainConfig2
person
多例模式下:
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
mainConfig2
person
给容器中添加Person...
给容器中添加Person...
false
结论:
1、默认在单例模式下ioc容器会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中拿
2、多实例模式下,ioc容器启动并不会调用方法创建对象放入容器中,而是每次获取才调用方法创建对象,
每次调用的都是新实例
三、@lazy-bean懒加载(针对单实例bean)
单实例bean:默认在容器启动的时候创建对象;
懒加载:容器启动不创建对象,第一次获取(使用)bean创建对象,并初始化
测试(无懒加载):
// @Lazy
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person...");
return new Person("张三",25);
}
测试类:
@Test
public void test02(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("ioc容器创建完成");
}
}
结果:在容器创建前初始化bean
给容器中添加Person...
ioc容器创建完成
测试(有懒加载)结果:未初始化bean
ioc容器创建完成
测试(有懒加载,后来调用):
ioc容器创建完成
给容器中添加Person...
Person{name='张三', age=25}