山寨一个Spring的@Component注解

1. 前言
我们在上一篇对Mybatis如何将Mapper接口注入Spring IoC进行了分析,有同学问胖哥这个有什么用,这个作用其实挺大的,比如让你实现一个类似@Controller的注解(或者继承某个统一接口)来完成比如定时任务的统一注入或者Websocket处理器的统一注入等这种将某种共性的Bean动态注入。
// 模仿 Controller
@XBean(description = "ETL JOB")
public class JobShedule {
@Caller(cron = "* * 0/5 * * ?")
public void exec(){
// job
}
}
以上伪代码就是一个模仿Controller的定时任务Bean。
2. 设计思路
详细的开发设计思路我已经总结好了,各位同学只要按部就班就可以实现这个功能了。
2.1 定义扫描注解
定义一个类似@MappScan的进行导入自定义ImportBeanDefinitionRegistrar,并指定扫描包范围。
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Import(XBeanDefinitionRegistrar.class)
public @interface XBeanScan {
String[] basePackages();
}
我们自定义了一个扫描注解@XBeanScan。它有两个作用:
- 通过
basePackages指定扫描包的范围。 - 导入我们自定义
ImportBeanDefinitionRegistrar的实现XBeanDefinitionRegistrar。
2.2 定义目标Bean的通用标记
通常我们可以选择一个标识接口,所有其实现类都会注入Spring IoC;或者用更加方便的注解,所有被该注解标记的类都将注入Spring IoC。这里我们使用更加灵活方便的注解,实现了一个@XBean标记注解:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface XBean {
String description() default "";
}
2.3 实现扫描器
Spring框架为我们提供了扫描器来注册被标记的Bean,它就是上节提到的ClassPathBeanDefinitionScanner,我们继承它进行稍加改造:
public class XBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public XBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
super(registry, useDefaultFilters);
super.addIncludeFilter(new AnnotationTypeFilter(XBean.class));
}
}
这里我们不使用默认的过滤器,我们指定了扫描器扫描的目标为被@XBean标记的那些Bean。
2.4 实现 Bean 注册机
重头戏来了,我们需要将2.1到2.3定义的这些组件在ImportBeanDefinitionRegistrar的实现中组装起来。
/**
* The type X bean definition registrar.
*
* @author felord.cn
* @since 2020 /9/18 22:59
*/
public class XBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 不使用默认过滤器
XBeanDefinitionScanner xBeanDefinitionScanner = new XBeanDefinitionScanner(registry, false);
xBeanDefinitionScanner.setResourceLoader(resourceLoader);
// 扫描XBeanScan注解指定的包
xBeanDefinitionScanner.scan(getBasePackagesToScan(importingClassMetadata));
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
* 获取{@link XBeanScan}中声明的扫描包路径
* @param metadata the meta
* @return 包路径数组
*/
private String[] getBasePackagesToScan(AnnotationMetadata metadata) {
String name = XBeanScan.class.getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes.getStringArray("basePackages");
}
}
从注解元数据importingClassMetadata解析我们需要的扫描路径basePackages等元数据,然后让扫描器在该路径扫描即可。
2.5 使用
在具有@Configuration标记的类或者Spring Boot的Main类上使用@XBeanScan即可,是不是非常简单!
其实
@ComponentScan提供类似的功能。
3. 总结
本篇是对上一篇理论的具体应用,说实话上一篇比较枯燥甚至抓不住重点,但是有时候理论就是这样的。一旦你结合本篇来看你会恍然大悟。如果你需要更加细粒度控制就加上那些BeanDefinitionRegistryPostProcessor和FactoryBean等Spring提供的功能性接口。从这两篇中更多需要你学习的是如何从阅读源码中触类旁通,来利用已有的组件来实现自己的逻辑。这对你的提高是极大的。好了今天就到这里,多多关注:码农小胖哥 更多干货等着你。
关注公众号:Felordcn 获取更多资讯
山寨一个Spring的@Component注解的更多相关文章
- Spring Boot@Component注解下的类无法@Autowired的问题
title: Spring Boot@Component注解下的类无法@Autowired的问题 date: 2019-06-26 08:30:03 categories: Spring Boot t ...
- Spring中@Component注解,@Controller注解详解
在使用Spring的过程中,为了避免大量使用Bean注入的Xml配置文件,我们会采用Spring提供的自动扫描注入的方式,只需要添加几行自动注入的的配置,便可以完成 Service层,Controll ...
- Spring中@Component注解,@Controller注解详解
在使用Spring的过程中,为了避免大量使用Bean注入的Xml配置文件,我们会采用Spring提供的自动扫描注入的方式,只需要添加几行自动注入的的配置,便可以完成 Service层,Controll ...
- spring中@Component注解
1.@controller 控制器(注入服务) 2.@service 业务(注入dao) 3.@repository dao(实现dao访问) 4.@component (把普通pojo实例化到spr ...
- Spring Boot 之注解@Component @ConfigurationProperties(prefix = "sms") 使用@ConfigurationProperties读取yml配置
从spring-boot开始,已经支持yml文件形式的配置,@ConfigurationProperties的大致作用就是通过它可以把properties或者yml配置直接转成对象 @Componen ...
- 0000 - Spring 中常用注解原理剖析
1.概述 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来 ...
- Spring 中常用注解原理剖析
前言 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来配置 ...
- java spring mvc 全注解
本人苦逼学生一枚,马上就要毕业,面临找工作,实在是不想离开学校.在老师的教导下学习了spring mvc ,配置文件实在繁琐,因此网上百度学习了spring mvc 全注解方式完成spring的装配工 ...
- Spring 中 @EnableXXX 注解的套路
前言 在 Spring 框架中有很多实用的功能,不需要写大量的配置代码,只需添加几个注解即可开启. 其中一个重要原因是那些 @EnableXXX 注解,它可以让你通过在配置类加上简单的注解来快速地开启 ...
随机推荐
- go语言之函数及闭包
一:函数 1 概述: 函数是 Go 程序源代码的基本构造单位,一个函数的定义包括如下几个部分,函数声明关键字 也町. 函数名.参数列表.返回列表和函数体.函数名遵循标识符的命名规则, 首字母的大小写决 ...
- JDBC | 第七章: JDBC数据库连接池使用
概述 数据库连接池是负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个.那么其中的运行机制又是怎样的呢?今天主要介绍一下数据库连接池原理和常用的连接池. ...
- 浅析一个lua文件窥slua工作机制
slua的东西不是几句话能讲得完,这里只说结论不说原因,原因有空写个Little Slua工程来解释,下面注释中有几个关键点:LuaVar系列类:LuaFunction,LuaTable,LuaDel ...
- 笔记-Linux 内存优化
1.清理前内存使用情况 free -m2.开始清理 echo 1 > /proc/sys/vm/drop_caches 3.清理后内存使用情况 free -m 4.完成! 查看内存条数命令: d ...
- JVM内存区域与垃圾回收
1.JAVA内存区域与内存溢出 1.1.概述 Java中JVM提供了内存管理机制,Java虚拟机在执行Java程序的过程中会把内分分为不同的数据区,如图: 1.2.程序计数器 程序计数器是当前线程所执 ...
- Vue中父组件使用子组件的emit事件,获取emit事件传出的值并添加父组件额外的参数进行操作
需求是这样的,需要输入这样一个列表的数据,可以手动添加行,每一行中客户编号跟客户姓名是自动关联的,就是说选取了客户姓名之后,客户编号是自动填充的,客户姓名是一个独立的组件,每一个下拉项都是一个大的对象 ...
- 20190925-05Redis五大数据类型之String 000 026
- @RequestBody使用说明
@RequestBody 使用 @RequestBody这个对于一般刚接触来说,确实有点陌生,但是现在前端,后端技术分的太细,越来越多的技术层出不穷,前端就分化出POST ,GET,PUT,DELET ...
- jmeter连数据库
前提:jmeter不能直接连数据库,需要导入一个jar包 步骤: 1.右键线程组--添加--配置元件--JDBC Connection Configuration 2.jdbc的基本配置:可以修改jd ...
- mock接口开发——flask模块
1.mock接口开发: #1.模拟没有开发好的接口,你可以模拟它,,,,,,,需要调用其他系统的接口 #2.给别人提供数据 2.步骤:1.安装pip install flask 2.导入模块--起服务 ...