Fork me on GitHub

Spring注解:@Configuration,@Bean,@ComponentScan(),@Scope

传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:
1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。总之这将导致配置文件的可读性与可维护性变得很低。
2、在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。
为了解决这两个问题,Spring引入了注解,通过”@XXX”的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。

所有的注解都是在一个工程中进行演示、后面不懂得可以参考前面的随笔!

开始注解的代码编程:

1.工程准备

Person.class

1
2
3
4
5
public class Person {    
private String name;
private int age;
...
}

配置类:

Config.class

1
2
3
4
5
6
7
8
9
10
11
12
13
//配置类 === 配置文件xxx.xml
//@Configuration是告诉Spring这是一个配置类
@Configuration
public class Config {

//给容器注册一个bean,相当于配置文件的 <bean></bean>
//类型默认是返回的类型
//id默认是方法名
@Bean("per")
public Person person(){
return new Person("MrChengs",20);
}
}

测试:

1
2
3
ApplicationContext app = new  AnnotationConfigApplicationContext(Config.class);
Person p =app.getBean(Person.class);
System.out.println(p);

Person [name=MrChengs, age=20]

  1. @Configuration

告诉sprin该类是一个配置类

所谓的配置类相当于我们所写的xxx.xml配置文件

  1. @Bean

给容器中注入一个Bean,相当于进行实例化一个bean

属性:

默认value可以不写

Spring注解:@Configuration,@Bean,@ComponentScan(),@Scope

  1. @ComponentScan()

    等同于:<context:component-scan base-package=””>

新建四个类,分别使用:@Repository,@Service,@Controller三个注解

1
2
3
4
5
6
7
8
9
@Repository
public class CustomerDao {
}
@Service
public class CustomerService {
}
@Controller
public class CustomerConteoller {
}

在Config.class类中

1
2
3
4
5
6
7
8
9
10
@Configuration
@ComponentScan(value="coom.MrChengs.config",excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Repository.class})})
public class Config {

@Bean("per")
public Person person(){
return new Person("MrChengs",20);
}
}
1
@ComponentScan:

value :指定需要扫描的包

excludeFilters :指定扫描的适合排除那些包

    Filter[] excludeFilters() default {};

  FilterType type() default FilterType.ANNOTATION;

​ Class<?>[] classes() default {};

includeFilters: 指定扫描的时候只包含那些包

  在使用的时候需要添加:useDefaultFilters=false属性

  其余属性和excludeFilters类似

1
2
3
4
5
6
7
8
9
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(Config.class);
//获取bean的name
String [] names = app.getBeanDefinitionNames();
for(String name : names){
System.out.println(name);
}
}
1
2
3
4
5
> config
> customerConteoller
> customerService
> per
>

关于@Filter的使用:

1
2
3
4
5
6
1.type=FilterType.ANNOTATION: 是根据注解的规则
2.type=FilterType.ASSIGNABLE_TYPE:按照给定的类型
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes=CustomerService.class
3.type=FilterType.ASPECTJ:使用aspectj表达式
4.type=FilterType.REGEX:使用正则表达式
5.type=FilterTyoe.CUSTOM:自定义规则

使用5进行测试:

1
2
3
@ComponentScan(value="coom.MrChengs.config",includeFilters={
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class}),
},useDefaultFilters=false)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MyTypeFilter implements TypeFilter{
//MetadataReader:读取到当前正在扫描的包信息
//MetadataReaderFactory:可以获取到其他类的任何信息
public boolean match(MetadataReader arg0, MetadataReaderFactory arg1) throws IOException {
//获取当前类的注解信息
AnnotationMetadata annotationMetadata =arg0.getAnnotationMetadata();
//获取当前正在扫描类的信息
ClassMetadata classMetadata = arg0.getClassMetadata();
//获取当前类的资源(路径,url...)
Resource resource = arg0.getResource();

//获取类的全类名
//扫描到的类
String className = classMetadata.getClassName();
System.out.println("--->" + className);
return false;
}
}

在测试打印的时候

这些都是className中打印出来的

扫描到的类

1
2
3
4
--->coom.MrChengs.config.conteoller.CustomerConteoller
--->coom.MrChengs.config.dao.CustomerDao
--->coom.MrChengs.config.MyTypeFilter
--->coom.MrChengs.config.service.CustomerService

return true的时候

当然我们可以进行系统的判断进行放行

1
2
3
4
5
config
customerConteoller
customerDao
myTypeFilter
customerService

可以把所有的@ComponentScan都写在里面

1
2
3
@ComponentScans(value={@ComponentScan(value="coom.MrChengs.config",excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Repository.class})})}
)

4.@Scope 调整作用域

Config2.java

1
2
3
4
5
6
7
8
@Configuration
public class Config2 {

@Bean("per")
public Person person(){
return new Person("MrChengs",20);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test2(){
ApplicationContext app = new AnnotationConfigApplicationContext(Config2.class);
String [] names = app.getBeanDefinitionNames();
for(String name : names){
System.out.println(name);
}
Person p = (Person) app.getBean("per");
Person p1 = (Person) app.getBean("per");
System.out.println(p == p1);

}
1
2
3
config2
per
true

说明默认是单实例的,只实例化一个bean

@Scope

1
2
3
4
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE   
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION

//prototype 多实例的 在IOC容器创建之后获取对象才开始创建,获取一次创建一次

//singleton 单例的 IOC容器启动的时候就会调用对象放到IOC容器中,多次获取也是只获取同一个

//request 同一次请求

//session 同一个session

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class Config2 {
//prototype 多实例的
//singleton 单例的
//request
//session
@Scope(value="prototype")
@Bean("per")
public Person person(){
return new Person("MrChengs",20);
}
}
1
2
3
config2
per
false

多实例情况下,获取一次则创建一个实例

原文链接

相关文章

微信打赏

赞赏是不耍流氓的鼓励

评论系统未开启,无法评论!