@ComponentScan注解 -【Spring底层原理
关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视
案例已上传GitHub,欢迎star:https://github.com/oneStarLR/spring-annotation
一、注解用法
1. 背景知识
什么是组件?
组件也是抽象的概念,可以理解为一些符合某种规范的类组合在一起就构成了组件,他可以提供某些特定的功能,但实际他们都是类,只不过有他们特殊的规定。组件和类的关系:符合某种规范的类的组合构成组件。
2. @ComponentScan注解作用
1. 将组件自动加载到容器
加了包扫描@ComponentScan注解后,只要标注了@Controller、@Service、@Repository、@Component注解中的任何一个,其组件都会被自动扫描,加入到容器中。
2. 通过属性指定扫描
【1】value
:指定要扫描的包
【2】excludeFilters=Filter[ ]
:设置排除的过滤条件,指定扫描的时候按照什么规则排除哪些组件,不扫描哪些包
【3】includeFilters=filter[ ]
:设置扫描过滤条件,指定扫描的时候按照什么规则包含哪些组件,满足该条件才进行扫描
【4】自定义过滤规则
:通过实现TypeFilter接口,自定义过滤规则
下面咱们通过实例来分析一下@ComponentScan注解的作用
二、实例分析
以maven项目为例,通过@ComponentScan、@Controller、@Service、@Repository注解获取容器中的对象:
// 启动类
@Test
public void TestMain(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
for(String beanName : beanNames){
System.out.println(“容器中对象名称:”+beanName);
}
}
// 配置类
@Configuration
@ComponentScan(value = “com.onestar”)
public class AppConfig {
}
// 控制层
@Controller
public class UserController {
}
// 业务层
@Service
public class UserService {
}
// 持久层
@Repository
public class UserDao {
}
运行测试类,可以看到如下打印信息,除了spring启动时注入到容器的对象外,还有我们自己加了注解,被spring扫描,加入到容器中
@ComponentScan(value = "com.onestar")
:value表示指定要扫描的包
点进@ComponentScan注解源码,我们可以看到,使用value可以指定要扫描的包,我们还可以排除要扫描的包,包含要扫描的包,甚至还可以自定义过滤规则
-
excludeFilters=Filter[ ]
:指定扫描的时候按照什么规则排除哪些包 -
includeFilters=filter[ ]
:指定扫描的时候是需要包含哪些包
【@ComponentScan源码】
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
// 扫描路径
@AliasFor(“basePackages”)
String[] value() default {};
// 扫描路径
@AliasFor(“value”)
String[] basePackages() default {};
// 指定扫描类
Class<?>[] basePackageClasses() default {};
/**
* 命名注册的Bean,可以自定义实现命名Bean,
* 1、@ComponentScan(value = “spring.annotation.componentscan”,nameGenerator = MyBeanNameGenerator.class)
* MyBeanNameGenerator.class 需要实现 BeanNameGenerator 接口,所有实现BeanNameGenerator 接口的实现类都会被调用
* 2、使用 AnnotationConfigApplicationContext 的 setBeanNameGenerator方法注入一个BeanNameGenerator
* BeanNameGenerator beanNameGenerator = (definition,registry)-> String.valueOf(new Random().nextInt(1000));
* AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
* annotationConfigApplicationContext.setBeanNameGenerator(beanNameGenerator);
* annotationConfigApplicationContext.register(MainConfig2.class);
* annotationConfigApplicationContext.refresh();
* 第一种方式只会重命名@ComponentScan扫描到的注解类
* 第二种只有是初始化的注解类就会被重命名
* 列如第一种方式不会重命名 @Configuration 注解的bean名称,而第二种就会重命名 @Configuration 注解的Bean名称
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* 用于解析@Scope注解,可通过 AnnotationConfigApplicationContext 的 setScopeMetadataResolver 方法重新设定处理类
* ScopeMetadataResolver scopeMetadataResolver = definition -> new ScopeMetadata(); 这里只是new了一个对象作为演示,没有做实际的逻辑操作
* AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
* annotationConfigApplicationContext.setScopeMetadataResolver(scopeMetadataResolver);
* annotationConfigApplicationContext.register(MainConfig2.class);
* annotationConfigApplicationContext.refresh();
* 也可以通过@ComponentScan 的 scopeResolver 属性设置
*@ComponentScan(value = “spring.annotation.componentscan”,scopeResolver = MyAnnotationScopeMetadataResolver.class)
*/
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
// 设置类的代理模式
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
/**
* 扫描路径 如 resourcePattern = “**/*.class”
* 使用 includeFilters 和 excludeFilters 会更灵活
*/
String resourcePattern() default “**/*.class”;
/**
* 指示是否应启用对带有{@code @Component},{@ code @Repository},
* {@ code @Service}或{@code @Controller}注释的类的自动检测。
*/
boolean useDefaultFilters() default true;
/**
* 对被扫描的包或类进行过滤,若符合条件,不论组件上是否有注解,Bean对象都将被创建
* @ComponentScan(value = “com.onestar”,includeFilters = {
* @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}),
* @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserDao.class}),
* @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}),
* @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = “spring.annotation…*”),
* @ComponentScan.Filter(type = FilterType.REGEX, pattern = “1+Dao$”)
* },useDefaultFilters = false)
* useDefaultFilters 必须设为 false
*/
ComponentScan.Filter[] includeFilters() default {};
// 设置排除的过滤条件,指定扫描的时候按照什么规则排除哪些组件,排除要扫描的包,用法参考includeFilters
ComponentScan.Filter[] excludeFilters() default {};
/**
* 指定是否应注册扫描的Bean以进行延迟初始化。
* @ComponentScan(value = “com.onestar”,lazyInit = true)
*/
boolean lazyInit() default false;
// @Filter注解,用于 includeFilters 或 excludeFilters 的类型筛选器
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
/**
* 要使用的过滤器类型,默认为 ANNOTATION 注解类型
* @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
*/
FilterType type() default FilterType.ANNOTATION;
/**
* 过滤器的参数,参数必须为class数组,单个参数可以不加大括号
* 只能用于 ANNOTATION 、ASSIGNABLE_TYPE 、CUSTOM 这三个类型
* @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class})
* @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserDao.class})
* @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
*/
@AliasFor(“classes”)
Class<?>[] value() default {};
/**
* 作用同上面的 value 相同
* ANNOTATION 参数为注解类,如 Controller.class, Service.class, Repository.class
* ASSIGNABLE_TYPE 参数为类,如 UserDao.class
* CUSTOM 参数为实现 TypeFilter 接口的类 ,如 MyTypeFilter.class
* MyTypeFilter 同时还能实现 EnvironmentAware,BeanFactoryAware,BeanClassLoaderAware,ResourceLoaderAware
* 这四个接口
* EnvironmentAware
* 此方法用来接收 Environment 数据 ,主要为程序的运行环境,Environment 接口继承自 PropertyResolver 接口,
* 详细内容在下方
* @Override
* public void setEnvironment(Environment environment) {
* String property = environment.getProperty(“os.name”);
* }
*
* BeanFactoryAware
* BeanFactory Bean容器的根接口,用于操作容器,如获取bean的别名、类型、实例、是否单例的数据
* @Override
* public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
* Object bean = beanFactory.getBean(“BeanName”)
* }
*
* BeanClassLoaderAware
* ClassLoader 是类加载器,在此方法里只能获取资源和设置加载器状态
* @Override
* public void setBeanClassLoader(ClassLoader classLoader) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后总结
ActiveMQ+Kafka+RabbitMQ学习笔记PDF
关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
Q实战指南
[外链图片转存中…(img-l8PZc8GO-1711959311276)]
[外链图片转存中…(img-HS4Xg7y9-1711959311276)]
[外链图片转存中…(img-6GBAf9Vo-1711959311276)]
关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
A-Za-z. ↩︎
更多推荐
所有评论(0)