1、简介
我们开发一直在用@Repository、@Service、@Component、@Controller
四个注解,我们也知道要想让这四个注解生效必须配置context:component-scan>
标签。这节让注解代替此配置。
2、项目结构
3、基础类
@Repository
public class BookDAO {
}
@Service
public class BookService {
}
@Controller
public class BookController {
}
4、配置文件的方式
4.1、配置文件
4.2、测试类
private static final String CONFIG = "classpath:component/beans.xml";
@Test
public void test1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(CONFIG);
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
4.3、运行结果
bookController
bookDAO
bookService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
PS:
我们可以看到
bookController
bookDAO
bookService但是我们还看了一些其他的类,那些是Spring内置类,先不管。
5、注解的方式
5.1、配置类
/**
* @ComponentScan注解,就代替了这个标签
*
* 里面的value值等同于 base-package="com.chentongwei.spring.annotation.component",为什么不是basePackages而是value呢? 我们看下源码
*
* @AliasFor("basePackages")
* String[] value() default {};
*
* @AliasFor("value")
* String[] basePackages() default {};
*
* 可以看出value==basePackages,因为用了@AliasFor注解,代表别名的意思。
*/
@ComponentScan(value = "com.chentongwei.spring.annotation.component")
public class MainConfig {
}
5.2、测试类
@Test
public void test2() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
5.3、运行结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDAO
bookService
PS:
我们可以看到比上面配置文件的方式多出了一个mainConfig,这是为什么呢?是因为我们MainConfig类被@ComponentScan注解所修饰。
6、高级
6.1、简介
我们知道配置文件的方式可以指定排除哪些包或者哪些类等,只包含哪些包或哪些类等等这些操作。那么注解的方式一样支持。
6.2、排除
6.2.1、需求
排除被注解Service或者Controller所修饰的类。
6.2.2、配置类
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class, Controller.class})
}
)
public class MainConfig {
}
PS:
excludeFilters属性
6.2.3、测试类
同【5.2、测试类】
6.2.4、输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookDAO
PS:
bookService和bookController不见了。
6.3、只包含
6.3.1、需求
只注册包含注解Repository所修饰的类。
6.3.2、配置类
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Repository.class})
}
)
public class MainConfig {
}
PS:
includeFilters属性
6.3.3、测试类
同【5.2、测试类】
6.3.4、输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDAO
bookService
PS:
没起作用,为嘛呢?我们回想一下配置文件的方式是不是也不起作用,答案:是的。因为我们需要禁用默认配置,同样的注解方式也需要禁用掉默认配置,源码采取的是默认配置,如下:
boolean useDefaultFilters() default true;
6.3.5、修改配置类
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Repository.class})
}
)
public class MainConfig {
}
6.3.6、测试类
同【5.2、测试类】
6.3.7、输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookDAO
6.4、其他
我们不只是能按照注解的方式来配置包含排除,我们还可以按照正则表达式的方式,不举例。
7、补充
如何同时制定多个@ComponentScan?
有两种方式:
7.1、Java8支持注解继承
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Repository.class})
}
)
@ComponentScan(
value = "com.chentongwei.spring.annotation.test",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})
}
)
public class MainConfig {
}
PS:
太明显了,两个注解混用,第一个扫描component包下的Repository注解,第二个扫描test包下的Service注解,两个会自动结合(Java8继承)。
7.2、@ComponentScans
@ComponentScans(
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Repository.class})
}
),
@ComponentScan(
value = "com.chentongwei.spring.annotation.test",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})
}
)
)
public class MainConfig {
}
PS:
采取@ComponentScans注解,包含多个@ComponentScan。
8、细说FilterType过滤规则
8.1、FilterType源码
public enum FilterType {
/**
* 注解
*/
ANNOTATION,
/**
* 类型
*/
ASSIGNABLE_TYPE,
/**
* ASPECTJ的方式
*/
ASPECTJ,
/**
* 正则表达式
*/
REGEX,
/**
* 自定义规则
*/
CUSTOM
}
PS:
不难发现我们可以使用如上那些方式来指定过滤规则,上面我们一直讲解的是第一种:ANNOTATION注解的方式,接下来我们说下其他几种。
8.2、ASSIGNABLE_TYPE
8.2.1、需求
只要是BookService类型的都加载。
8.2.2、代码
@Service
public class BookService {
}
public class BookServiceImpl extends BookService {
}
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
}
)
public class MainConfig {
}
8.2.3、输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookService
bookServiceImpl
8.2、ASPECTJ
用的不多,不讲解。
8.3、REGEX
正则表达式,随用随Google,不举例。
8.4、CUSTOM
8.4.1、需求
只要是类名包含“er”的都加载。
8.4.2、代码
/**
* 自定义过滤规则需要实现TypeFilter接口。并重写match方法进行匹配,返回true的就加载,返回false的排除。
*
* 可以利用metadataReader和metadataReaderFactory来获取到类的任何信息,以此来书写过滤规则来判断是否需要加载。
*/
public class MyTypeFilter implements TypeFilter {
/**
* @param metadataReader:读取到的当前正在扫描的类的信息
* @param metadataReaderFactory:获取到其他任何类信息
* @return
* @throws IOException
*/
@Override
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:---->" + className);
if (className.contains("er")) {
return true;
}
return false;
}
}
@ComponentScan(
value = "com.chentongwei.spring.annotation.component",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}
)
public class MainConfig {
}
8.4.3、输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
myTypeFilter
bookController
bookService
bookServiceImpl
9、广告
-
码云点star,万分感谢!
代码已经上传到码云了
https://gitee.com/geekerdream/spring-anonation
通用的权限处理框架
https://gitee.com/geekerdream/common-security
通用的异常处理
https://gitee.com/geekerdream/exception-handler
通用的发送邮件
https://gitee.com/geekerdream/common-boot-email
陆续会推出更多干货,希望关注!
QQ群【Java初学者学习交流群】:458430385
微信公众号【Java码农社区】
- 今日头条号:编程界的小学生