从Spring的包扫描说起

SpringBoot会扫描SpringBootApplication注解标注的类,他所在的包以及这个包的子包,把那里面的Bean注册到applicationContext中,然而,在一个相对大型的项目中,Bean会很多,而且一些框架在starter中会有比较特别的配置(例如Jackson框架)。

那么,我想有没有什么办法可以限制这些Bean的活动范围,让一个模块的Bean仅仅在自己的区域起效,而不会在整个Context内四处乱来。

Spring中有一个父子容器的关系,子容器能够访问父容器,而父容器不能访问子容器,子容器之间当然也是相互隔开的,那么这就是一个很好的实现方法了。

首先,想办法限制父容器的扫描范围,让他不扫描某些Bean,然后使用BeanPostProcessor判别注解,然后根据注解建立子容器,并且扫描子容器的包范围内的Bean,子容器提供一个接口托管到父容器中,所有子容器就可以通过这些在父容器某模块的接口来相互使用其他子容器模块提供的服务,这样Bean就被限制在了自己模块的范围之内了。

初步实现

定义一个注解,用它来描述一个Spring的Bean,待会这个注解会在扫描的时候被排除在外。

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import org.springframework.stereotype.Component; @Retention(RUNTIME)
@Target(TYPE)
@Component
public @interface SubComp { }

然后在SpringBootApplication下方标注:

@SpringBootApplication
@ComponentScan(excludeFilters=@Filter(type=FilterType.ANNOTATION,value=SubComp.class))

那么,接下来使用这个注解代替@Component@Service@Controller之类的,这样组件就不会被Spring扫描到了。

接下来,定义一个BeanPostProcessor,通过它来查找带有@Configuration的Bean,然后在发现这个注解的时候创建新的AnnotationApplicationContext,然后扫描这个Bean的包,这样,新注解标注的Bean就会被这个Context发现并且注册,最后,让这个Context成为子容器,附属于SpringBootApplication的Context。

@Component
public class RangeProcesser implements BeanPostProcessor,ApplicationContextAware{ private ApplicationContext applicationContext;
private List<ApplicationContext> contexts = new ArrayList<>(); @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean.getClass().getAnnotation(Configuration.class)!=null) {
AnnotationConfigApplicationContext subContext = new AnnotationConfigApplicationContext(bean.getClass());
subContext.scan(bean.getClass().getPackage().getName());
subContext.start();
subContext.setParent(applicationContext);
contexts.add(subContext);
return null;
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
} @Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.applicationContext = ctx;
}
}

像这样,就有了一些子容器,父子容器关系的特点就是子容器可以访问父容器,反之不可,所以父容器在这里将会提供通用的组件,并且作为子容器相互沟通的桥梁。

未完待续。

SpringBoot:通过多个Context限制Bean的活动范围的更多相关文章

  1. 尚硅谷springboot学习10-@PropertySource,@ImportResource,@Bean

    @PropertySource 使用指定的属性文件而不一定是application.xxx 同样可以注入相关内容 @ImportResource 导入Spring的配置文件,让配置文件里面的内容生效: ...

  2. springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用

    这个需求应该也比较常见,在不同的条件下创建不同的bean,具体场景很多,能看到这篇的肯定懂我的意思. 倘若不了解spring4.X新加入的@Conditional注解的话,要实现不同条件创建不同的be ...

  3. SpringBoot配置——@PropertySource、@ImportResource、@Bean

    @PropertySource:加载指定的配置文件 package com.hoje.springboot.bean; import org.springframework.beans.factory ...

  4. SpringBoot框架(4)-- 类装配及Bean装配监听器

    1.普通方式装配类对象   (1)添加带有@Bean注解的方法  User.java(带@Component注解) package com.demo.boot.bootenable.beanDemo1 ...

  5. SpringBoot拦截器中无法注入bean的解决方法

    SpringBoot拦截器中无法注入bean的解决方法 在使用springboot的拦截器时,有时候希望在拦截器中注入bean方便使用 但是如果直接注入会发现无法注入而报空指针异常 解决方法: 在注册 ...

  6. springboot available: expected at least 1 bean which qualifies as autowire candidate奇葩问题

    Exception encountered during context initialization - cancelling refresh attempt: org.springframewor ...

  7. springboot中velocity tool中注入bean

    在使用springboo的时候,遇到一个问题,想在tool类中注入一个bean,一直失败,翻了下源码,是因为工具类的初始化方法为反射class调用newInstance方法,详见 http://www ...

  8. Spring-Boot基于配置按条件装Bean

    背景 同一个接口有多种实现,项目启动时按某种规则来选择性的启用其中一种实现,再具体一点,比如Controller初始化的时候,根据配置文件的指定的实现类前缀,来记载具体Service,不同Servic ...

  9. SpringBoot 配置 @PropertySource、@ImportResource、@Bean

    一.@PropertySource @PropertySource:加载指定的配置文件 @PropertySource(value = {"classpath:person.properti ...

  10. SpringBoot学习之@Configuration注解和@Bean注解

    @Configuration 1.@Configuration注解底层是含有@Component ,所以@Configuration 具有和 @Component 的作用. 2.@Configurat ...

随机推荐

  1. Java日期时间API系列20-----Jdk8中java.time包中的新的日期时间API类,ZoneId时区ID大全等。

    Java日期时间API系列19-----Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格 ...

  2. 墨天轮高分技术文档分享——Oracle升级迁移篇(共96个)

    朋友们好久不见,在上期<墨天轮最受欢迎的技术文档-SQL优化篇>的留言中,有许多朋友表示想看数据库升级迁移相关的内容,经过搜集整理,这就为大家呈上!原文送墨值中,欢迎大家参与~ 数据库升级 ...

  3. 使用 vuex 和 本地存储实现永久性token存在 并且在请求拦截统一添加headers token 避免重复代码

    在 vuex 仓库中设置state的token值:从本地中取值: 登录的时候调用唯一可以修改state数据的mutations方法设置token : export default new Vuex.S ...

  4. Newstar_week1-2_wp

    week1 wp crypto 一眼秒了 n费马分解再rsa flag: import libnum import gmpy2 from Crypto.Util.number import * p = ...

  5. Ubuntu 22.04 解决和 Windows 共享蓝牙设备的问题

    我有一个 Airpods,连接到 WIndows 可以正常工作,但连接到 ubuntu 后会无法连接,只能删除设备选择重联,但是这又会导致 Windows 不能连接到耳机,只能也删除重新连接,费神费力 ...

  6. A星、Floyod、Bellman-Ford

    A 星算法 A 星和 Dijkstra 算法唯一区别在于堆中排序的依据.distance 数组仍然保存实际代价,预估代价只影响堆的弹出顺序. Dijkstra 根据源点到当前点的实际代价进行排序. A ...

  7. java中如何将Object类型转换为int类型

    如何将Object类型转换为int类型 Object object = null; try { Integer.parseInt(object.toString()); } catch (Number ...

  8. 登陆mysql,Can 't connect to local MySQL server through socket '/tmp/mysql.sock '(2) "

    今天ssh到slave机器上,登陆mysql,遇到下图的报错. 查了一圈,最终解决办法简洁的出乎意料. 首先,要查看mysql服务是否已经启动(真的太容易漏掉) 第2步,你可能会自然而然的以为密码也是 ...

  9. 腾讯云禁止root用户登录

    背景 买了腾讯云的云主机服务,装的 OpenCloudOS 系统,结果没几天就提示异常登录和恶意文件.结果还改了我的密码,导致我xshell登陆不了,通过腾讯云后台登进去发现有挖矿病毒,但还没完全跑起 ...

  10. 基于Java+SpringBoot+Mysql实现的古诗词平台功能设计与实现四

    一.前言介绍: 1.1 项目摘要 随着信息技术的迅猛发展和数字化时代的到来,传统文化与现代科技的融合已成为一种趋势.古诗词作为中华民族的文化瑰宝,具有深厚的历史底蕴和独特的艺术魅力.然而,在现代社会中 ...