zoukankan      html  css  js  c++  java
  • SpringBoot:通过多个Context限制Bean的活动范围

    从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;
    	}
    }
    

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

    未完待续。

  • 相关阅读:
    广告效果滚动
    判断背景图片是否加载成功
    css3创建多边形clip属性,可用来绘制不规则图形了
    不允许用户选中文本的两种方法
    栈类模板设计及应用
    HDOJ 题目类型
    极大团数量模板
    HDU 1522 Marriage is Stable 稳定婚姻匹配
    字符串类设计与应用
    正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)
  • 原文地址:https://www.cnblogs.com/exmyth/p/14311970.html
Copyright © 2011-2022 走看看