在Project下面找到一个resources 文件夹创建一个beans.xml (xml的文件名随意)。如下,把你需要加载的bean 插入到bean节点下面。定义id 和 class类。当application被创建的时候,他就会去扫对应的xml文件,将这里定义的bean加载到IOC容器。
测试方式:(xml形式 需要使用ClassPathXmlApplicationContext)
ApplicationContext appxml = new ClassPathXmlApplicationContext("beans.xml");
Person person = appxml.getBean("person", Person.class);
System.out.println(person.toString());
注解1:@Configuration 作用于类,被这个注解标注的类可以理解成beans.xml
注解2:@Bean 作用于方法,主要作用往IOC容器中注册一个Bean, 值是id 返回值是Bean的类型
@Configuration
public class MainConfig {
@Bean("springPerson")
public Person getPerson(){
return new Person("spring",17);
}
}
测试方式:
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
Person springPerson = (Person) app.getBean("springPerson");
System.out.println(springPerson.toString());
String[] beanNamesForType = app.getBeanNamesForType(Person.class);
for (String name : beanNamesForType) {
System.out.println(name);
}
作为一个小白,第一次看到这样的操作注解,并不知道这里有什么作用。
通过注解我们可以定义配置类也就是Configuration可以扫描到那些类。以MVC为例我一般会定义 Controller、Service、Dao。 所以我们会定义很多这些相关的类,但是并不是所有类都需要加载到IOC容器。所谓Component 其实Controller、Service、Dao(Repository) 都是Component没有本质上的区别,就是一个类,注解被标记的时候,表明它的作用,起到一个提示作用。
如下目录结构:
-test2
-controller
OrderControlller.java
-dao
OrderDao.java
-service
OrderService.java
@Controller
public class OrderControlller {
}
@Repository
public class OrderDao {
}
@Service
public class OrderService {
}
接下来定义配置类
@Configuration
@ComponentScan(value = {"lsn01.cap02"}, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class Cap01MainConfig {
}
定义测试方式:
@Test
public void testComponentScan(){
ApplicationContext app = new AnnotationConfigApplicationContext(Cap02MainConfig.class);
String[] beanDefinitionNames = app.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName = "+beanDefinitionName);
}
}
1、value 配置扫码的包路径String[] value() default {}
2、includeFilters 包含哪些Filter。 可以通过定义type 和classs 指定哪些可以被扫描到。
如:@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
打印结果:
beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig
beanDefinitionName = orderControlller
beanDefinitionName = orderDao
beanDefinitionName = orderService
显然并没有起到一个过滤效果,依然把所有的组件全部扫描进来,而我们需要的只是包含Controller
注解的类。
原因在于 useDefaultFilters = false 设置,关闭到默认的Filters
beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig
beanDefinitionName = orderControlller
3、excludeFilters 不包含哪些Filters 注意:如果使用这个注解就不需要将设置成true 否则将不会扫描任何组件
如:
excludeFilters =
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class}),
useDefaultFilters = false
打印结果:
beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig
4、自定义Filters
public class CustomFilter implements TypeFilter {
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
//当前扫描类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
Set annotationTypes = annotationMetadata.getAnnotationTypes();
for (String annotationType : annotationTypes) {
System.out.println("annotationType : "+annotationType);
}
//当前扫描类的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
System.out.println("classMetadata className = "+className);
//当前扫描类的资源
Resource resource = metadataReader.getResource();
String filename = resource.getFilename();
System.out.println("filename = "+filename);
//返回true就是包含,false就是不包含
return false;
}
}
相关的自定义可以根据上面的三种信息定义属于的结果逻辑返回。
打印结果
classMetadata className = lsn01.cap02.config.CustomFilter
filename = CustomFilter.class
annotationType : org.springframework.stereotype.Controller
classMetadata className = lsn01.cap02.controller.OrderControlller
filename = OrderControlller.class
annotationType : org.springframework.stereotype.Repository
classMetadata className = lsn01.cap02.dao.OrderDao
filename = OrderDao.class
annotationType : org.springframework.stereotype.Service
classMetadata className = lsn01.cap02.service.OrderService
filename = OrderService.class
beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig
1、从打印结果上看我们可以看到 最先扫描的是CustomFilter
2、FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口>
scope 主要作用是定义Bean在IOC容器中的创建规则
prototype: 多实例:IOC容器启动并不会去调用方法创建对象放在容器中,而是每次获取的时候才会调用方法创建对象
singleton: 单实例(默认),IOC容器启动会调用方法创建对象放到IOC容器中以后每交获取就是直接从容器(理解成从map.get对象)中拿
request: 主要针对WEB应用,同一次请求创建一个实例
session: 同一个session创建一个实例
@Configuration
public class Cap02MainConfig {
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public Person person(){
System.out.println("创建了一个person对象");
return new Person();
}
}
@Test
public void testScope(){
ApplicationContext app = new AnnotationConfigApplicationContext(Cap02MainConfig.class);
System.out.println("IOC容器初始化完成了");
Person person1 = app.getBean("person", Person.class);
Person person2 = app.getBean("person", Person.class);
System.out.println("person1 == person2 is "+(person2 == person1));
}
打印结果:
如果不加,@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
创建了一个person对象
IOC容器初始化完成了
person1 == person2 is true
加@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
IOC容器初始化完成了
创建了一个person对象
创建了一个person对象
person1 == person2 is false
得出结论默认情况在AnnotationConfigApplicationContext创建的时候,Spring自动就完成了所有相关bean的创建,并且是单例类;如果加入Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 是多实例类,并且不是随着ApplicationContext的创建而创建。
@Configuration
public class Cap02MainConfig {
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Lazy
@Bean
public Person person(){
System.out.println("创建了一个person对象");
return new Person();
}
}
@Test
public void testScope(){
ApplicationContext app = new AnnotationConfigApplicationContext(Cap02MainConfig.class);
System.out.println("IOC容器初始化完成了");
Person person1 = app.getBean("person", Person.class);
Person person2 = app.getBean("person", Person.class);
System.out.println("person1 == person2 is "+(person2 == person1));
}
打印结果:
IOC容器初始化完成了
创建了一个person对象
person1 == person2 is true