Spring注解驱动开发【1】
@Configuration@Bean@ComponentScan@scope@Lazy
github源码下载:https://github.com/LuckyShawn/spring-annotation
一、先回顾用配置文件xml是如何注入一个bean并获取的。
- 创建一个Person类
package com.shawn.bean;
public class Person {
private String name;
private Integer age;
//省略get、set、toString方法
- 创建Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="bean.Person" scope="prototype" >
<property name="age" value="20"></property>
<property name="name" value="zhangsan"></property>
</bean>
</beans>
- 测试类
//利用配置文件的方式
@Test
public void test01(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) ac.getBean("person");
System.out.println(person);
}
结果:Person [name=zhangsan, age=20]
二、用注解@Configuration @Bean获取bean
- Config类 配置类==配置文件
@Configuration //告诉Spring这是一个配置类
public class Config01 {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person(){
return new Person("lise",20);
}
}
- 测试
//配置类的方式
@Test
public void test02(){
ApplicationContext ac = new AnnotationConfigApplicationContext(Config01.class);
Person person = (Person) ac.getBean("person");
System.out.println(person);
}
结果:Person [name=zhangsan, age=20]
//与配置文件结果一致
三、@ComponentScans自动扫描组件
包扫描、只要标注了@Controller、@Service、@Repository,@Component
- 编写主配置类
@Configuration //告诉Spring这是一个配置类 配置类==配置文件
//组件扫描 includeFilters:只需要哪些bean, useDefaultFilters = false 关闭默认过滤器
//包扫描、只要标注了@Controller、@Service、@Repository,@Component
@ComponentScans(
value = {
@ComponentScan(value="com.shawn",includeFilters = {
@ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class})
},useDefaultFilters = false)
}
)
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
public class Config01 {
@Bean("person") //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
public Person person(){
return new Person("lise",20);
}
}
- 新建用于测试的dao,service,controller
@Repository
public class BookDao {
}
@Service
public class BookService {
}
@Controller
public class BookController {
}
- 测试
@Test
public void test03(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config01.class);
//获取所有标注的bean
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
}
结果:
因为在扫描的时候我们注解@ComponentScan只需要BookService和Controller,所以没有bookDao这个bean
附:也可以使用@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})自定义规则进行过滤
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类信息的
*/
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("controller")){
return true;
}
return false;
}
四、@scope @Lazy
- 创建config02
@Configuration
public class Config02 {
//默认是单实例的
/**
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE prototype
* @see ConfigurableBeanFactory#SCOPE_SINGLETON singleton
* @see //org.springframework.web.context.WebApplicationContext SCOPE_REQUEST
* @see //org.springframework.web.context.WebApplicationContext SCOPE_SESSION
* @Scope:调整作用域
* prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
* 每次获取的时候才会调用方法创建对象;
* singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
* 以后每次获取就是直接从容器(map.get())中拿,
*
* Web环境下:
* request:同一次请求创建一个实例
* session:同一个session创建一个实例
*
* 懒加载:
* 单实例bean:默认在容器启动的时候创建对象;
* 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
*
*/
//@Lazy
@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("jack",18);
}
}
- 测试
//测试组件作用域
@Test
public void test04(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config02.class);
String [] names = applicationContext.getBeanDefinitionNames();
for(String name : names){
System.out.println(name);
}
Object person01 = applicationContext.getBean("person");
Object person02 = applicationContext.getBean("person");
System.out.println(person01 == person02);
//true 返回的是同一个实例
}