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.12.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 BootMain类上使用@XBeanScan即可,是不是非常简单!

其实@ComponentScan提供类似的功能。

3. 总结

本篇是对上一篇理论的具体应用,说实话上一篇比较枯燥甚至抓不住重点,但是有时候理论就是这样的。一旦你结合本篇来看你会恍然大悟。如果你需要更加细粒度控制就加上那些BeanDefinitionRegistryPostProcessorFactoryBeanSpring提供的功能性接口。从这两篇中更多需要你学习的是如何从阅读源码中触类旁通,来利用已有的组件来实现自己的逻辑。这对你的提高是极大的。好了今天就到这里,多多关注:码农小胖哥 更多干货等着你。

关注公众号:Felordcn 获取更多资讯

个人博客:https://felord.cn

山寨一个Spring的@Component注解的更多相关文章

  1. Spring Boot@Component注解下的类无法@Autowired的问题

    title: Spring Boot@Component注解下的类无法@Autowired的问题 date: 2019-06-26 08:30:03 categories: Spring Boot t ...

  2. Spring中@Component注解,@Controller注解详解

    在使用Spring的过程中,为了避免大量使用Bean注入的Xml配置文件,我们会采用Spring提供的自动扫描注入的方式,只需要添加几行自动注入的的配置,便可以完成 Service层,Controll ...

  3. Spring中@Component注解,@Controller注解详解

    在使用Spring的过程中,为了避免大量使用Bean注入的Xml配置文件,我们会采用Spring提供的自动扫描注入的方式,只需要添加几行自动注入的的配置,便可以完成 Service层,Controll ...

  4. spring中@Component注解

    1.@controller 控制器(注入服务) 2.@service 业务(注入dao) 3.@repository dao(实现dao访问) 4.@component (把普通pojo实例化到spr ...

  5. Spring Boot 之注解@Component @ConfigurationProperties(prefix = "sms") 使用@ConfigurationProperties读取yml配置

    从spring-boot开始,已经支持yml文件形式的配置,@ConfigurationProperties的大致作用就是通过它可以把properties或者yml配置直接转成对象 @Componen ...

  6. 0000 - Spring 中常用注解原理剖析

    1.概述 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来 ...

  7. Spring 中常用注解原理剖析

    前言 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来配置 ...

  8. java spring mvc 全注解

    本人苦逼学生一枚,马上就要毕业,面临找工作,实在是不想离开学校.在老师的教导下学习了spring mvc ,配置文件实在繁琐,因此网上百度学习了spring mvc 全注解方式完成spring的装配工 ...

  9. Spring 中 @EnableXXX 注解的套路

    前言 在 Spring 框架中有很多实用的功能,不需要写大量的配置代码,只需添加几个注解即可开启. 其中一个重要原因是那些 @EnableXXX 注解,它可以让你通过在配置类加上简单的注解来快速地开启 ...

随机推荐

  1. ent orm笔记4---Code Generation

    在前面几篇文章中,我们经常使用的可能就是entc这个命令了,entc这个工具给带来了很多功能,这篇文章主要整理关于ent orm 中Code Generation 之前的例子中有个知识点少整理了,就是 ...

  2. php实现无限极分类(多维数组 / 二维数组)形式

    <?php // 测试数组数据$array = array( array('id'=>'1','title'=>'父级分类1','pid'=>'0'), array('id'= ...

  3. Android开发之recycleView详解代码,看完包你熟练掌握recycleView的用法。转自网络经典文章

    来源 http://jinyudong.com/2014/11/13/Introduce-RecyclerView-%E4%B8%80/ 编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在 ...

  4. C# 自定义无边框窗体阴影效果

    工作中我们会经常遇到自定义一些窗口的样式,设置无边框然后自定义关闭.最大化等其他菜单,但是这样就失去了Winform自带的边框阴影效果,下面这个方法能让无边框增加阴影效果.代码如下: using Sy ...

  5. Mac系统下php.ini的位置

    http://blog.csdn.net/meegomeego/article/details/25704645 /private/etc/php.ini /usr/local/etc/php/5.5 ...

  6. 初级知识六——C#事件通知系统实现(观察者模式运用)

    观察者模式,绝对是游戏中十分重要的一种模式,运用这种模式,可以让游戏模块间的通信变得简单,耦合度也会大大降低,下面讲解如何利用C#实现事件通知系统. 补充,首先说下这个系统的实现原理,不然一头扎进去就 ...

  7. 【小白学PyTorch】6 模型的构建访问遍历存储(附代码)

    文章转载自微信公众号:机器学习炼丹术.欢迎大家关注,这是我的学习分享公众号,100+原创干货. 文章目录: 目录 1 模型构建函数 1.1 add_module 1.2 ModuleList 1.3 ...

  8. Linux服务器关联Git,通过执行更新脚本实现代码同步

    1.在Linux服务器安装Git yum install git -y   tips: 卸载Git :  yum remove git   2.在Linux生成ssh key   1)创建用户 git ...

  9. 10.redis cluster介绍与gossip协议

    一.redis cluster 介绍 自动将数据进行分片,每个 master 上放一部分数据 提供内置的高可用支持,部分 master 不可用时,还是可以继续工作的 redis cluster架构下的 ...

  10. 0 mysql 安装

    1 安装网址 https://dev.mysql.com/downloads/installer/ 选择 mysql server版本一路next 2.配置环境 mysql 默认安装位置是: C:\P ...