在一个项目开发中,一般会把项目分为
1、DAO层(数据访问层):专门负责数据库交互 CRUD(增查改删),比如在mysql数据库里生成一条订单数据。
2、Service层(业务逻辑层) : 负责业务逻辑的处理,比如购买东西的业务,需要调用DAO层的方法扣减商品记录里的库存数量,然后生成一条订单记录。
3、Controller层(控制层) : 接收页面的请求,调用业务逻辑层去处理,将业务逻辑层处理返回的结果返回给页面。
spring中对每一层都提供了相应的注解进行标识:
- @Repository 数据访问层
- @Service 业务逻辑层
- @Controller 控制层
spring还提供了 @Component 组件,没有明确的角色,只是标明该类要注册到spring容器中。
spring可以使用 @ComponentScan 注解扫描指定包下标有上面那些注解的类注册到spring容器中。
1、基础使用
下面配置类使用了包扫描注解@ComponentScan,并指定了扫描的包名为com.suzhe.spring.basic.scan, spring启动的时候就会扫描该包下所有的符合条件的类,并注入到spring容器中。
@Configuration //告诉Spring这是一个配置类
//包扫描:如果没有配置则默认扫描为当前类所在包及其子包
@ComponentScan(value = "com.suzhe.spring.basic.scan")
public class ScanConfig {
}
添加几个类:其中Message1 没有注解,不符合条件
@Controller public class GreetingController { }
@Service public class GreetingService { }
@Repository public class GreetingDao { public String getMessage(){ return "welcome"; } }
@Component public class Message { }
public class Message1 { }
运行测试
@Test
public void test1(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(ScanConfig.class);
//获取容器中所有注册的bean的name,返回一个数组
String[] names = app.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
}
可以看出spring把指定包下符合条件的类都注册到了容器中
值得注意的是,这些注解都有一个 value属性,是指定注册到spring中实例的name,默认为 类名首字母小写。
我们可以设置如下
@Service(value = "gs") public class GreetingService { }
再次运行测试,可以看到注册到spring中bean实例的name变成了gs。
同理,其他注解也一样。
2、扩展-包含过滤
注解@ComponentScan 还提供includeFilters属性指定扫描的时候只需要包含哪些组件。
其中Filter有下面几种过滤类型:
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型;
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则
示例配置类1
该类配置了FilterType.ANNOTATION和FilterType.ASSIGNABLE_TYPE ,那么就只有注解为@Service的类和Message会被注册到spring容器中。
需要注意的是useDefaultFilters设置为false。
@Configuration //告诉Spring这是一个配置类
//包扫描:如果没有配置则默认扫描为当前类所在包及其子包
@ComponentScan(value = "com.suzhe.spring.basic.scan",includeFilters ={
@ComponentScan.Filter(type= FilterType.ANNOTATION, classes={Service.class}),
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes={Message.class}),
}, useDefaultFilters=false)
public class ScanIncludeConfig {
}
测试运行
@Test
public void test2(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(ScanIncludeConfig.class);
String[] names = app.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
}
从下面的结果可以看出,只有两个符合过滤条件的类注入到了spring容器中。
同时我们还可以自定义过滤器,如下
public class CustomTypeFilter implements TypeFilter{
private ClassMetadata classMetadata;
/*
* MetadataReader:读取到当前正在扫描类的信息
* MetadataReaderFactory:可以获取到其他任何类信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类信息
classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("----->"+className);
if(className.contains("Controller")){//当类名包含Controller字符, 则匹配成功,返回true
return true;
}
return false;
}
}
通过FilterType.CUSTOM 指定过滤器CustomTypeFilter ,那么spring就只会注册符合CustomTypeFilter过滤条件的类。
@Configuration //告诉Spring这是一个配置类 //包扫描:如果没有配置则默认扫描为当前类所在包及其子包 @ComponentScan(value = "com.suzhe.spring.basic.scan",includeFilters ={ @ComponentScan.Filter(type=FilterType.CUSTOM,classes={CustomTypeFilter.class}), }, useDefaultFilters=false) public class ScanIncludeCustomConfig { }
测试运行
@Test public void test02(){ AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(ScanIncludeCustomConfig.class); String[] names = app.getBeanDefinitionNames(); for(String name:names){ System.out.println(name); } }
可以看到只有符合条件的GreetingController 被注册了。
同时@ComponentScan还提供了排除的过滤功能:
useDefaultFilters=true excludeFilters = Filter[] :指定扫描的时候按照什么规则排除哪些组件
includeFilters是包含哪些,excludeFilters是排除哪些,其他的都一样,这里不再做过多的说明。