Spring进阶(十八)之父子容器

目录

问题

什么是父子容器

BeanFactory的方式

ApplicationContext的方式

父子容器特点

使用父子容器解决开头的问题


问题

系统中有2个模块:module1和module2,两个模块是独立开发的,module2会使用到module1中的一 些类,module1会将自己打包为jar提供给module2使用,我们来看一下这2个模块的代码。

模块一:

@Component
public class Service1 {
    public String m1() {
        return "我是module1中的Service1中的m1方法";
    }
}
@Component
public class Service2 {
    @Autowired
    private Service1 service1; 

    public String m1() { 
        return this.service1.m1();
    }
}
@ComponentScan
public class module1Config {
}

模块二:

@Component
public class Service1 {

    public String m2() {
        return "我是module2中的Service1中的m2方法";
    }
}
@Component
public class Service3 {
    //使用模块2中的Service1
    @Autowired
    private Service1 service1; //

    //使用模块1中的Service2
    @Autowired
    private Service2 service2; 

    public String m1() {
        return this.service2.m1();
    }
    public String m2() {
        return this.service1.m2();
    }

}
@ComponentScan
public class module2Config {
}

测试:

    @Test
    void contextLoads() {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        context.register(module1Config.class,module2Config.class);

        context.refresh();
    }

运行后报错了:

Failed to parse configuration class [com.example.module2.module2Config]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'service1' for。。。

上面报错的原因是容器中的Service这个bean冲突了

那么我们如何解决?

对module1中的Service1进行修改?这个估计是行不通的,module1是别人以jar的方式提供给我们的, 源码我们是无法修改的。 而module2是我们自己的开发的,里面的东西我们可以随意调整,那么我们可以去修改一下module2中 的Service1,可以修改一下类名,或者修改一下这个bean的名称,此时是可以解决问题的。 不过大家有没有想过一个问题:如果我们的模块中有很多类都出现了这种问题,此时我们一个个去重 构,还是比较痛苦的,并且代码重构之后,还涉及到重新测试的问题,工作量也是蛮大的,这些都是风险。 而spring中的父子容器就可以很好的解决上面这种问题。

什么是父子容器

创建spring容器的时候,可以给当前容器指定一个父容器。

BeanFactory的方式

//创建父容器parentFactory
DefaultListableBeanFactory parentFactory = new DefaultListableBeanFactory();
//创建一个子容器childFactory
DefaultListableBeanFactory childFactory = new DefaultListableBeanFactory();
//调用setParentBeanFactory指定父容器
childFactory.setParentBeanFactory(parentFactory);

ApplicationContext的方式

//创建父容器
AnnotationConfigApplicationContext parentContext = new
AnnotationConfigApplicationContext();
//启动父容器
parentContext.refresh();
//创建子容器
AnnotationConfigApplicationContext childContext = new
AnnotationConfigApplicationContext();
//给子容器设置父容器
childContext.setParent(parentContext);
//启动子容器
childContext.refresh();

父子容器特点

  • 父容器和子容器是相互隔离的,他们内部可以存在名称相同的bean
  • 子容器可以访问父容器中的bean,而父容器不能访问子容器中的bean
  • 调用子容器的getBean方法获取bean的时候,会沿着当前容器开始向上面的容器进行查找,直到 找到对应的bean为止
  • 子容器中可以通过任何注入方式注入父容器中的bean,而父容器中是无法注入子容器中的bean, 原因就是第二条

使用父子容器解决开头的问题

关键代码:

@Test
    public void test2() {

        //创建父容器
        AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext();

        //向父容器中注册Module1Config配置类
        parentContext.register(module1Config.class);
        //启动父容器
        parentContext.refresh();
        
        //创建子容器
        AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
        //向子容器中注册Module2Config配置类
        childContext.register(module2Config.class);
        //给子容器设置父容器
        childContext.setParent(parentContext);
        //启动子容器
        childContext.refresh();
        
        //从子容器中获取Service3
        Service3 service3 = childContext.getBean(Service3.class);
        System.out.println(service3.m1());
        System.out.println(service3.m2());
    }

运行就不报异常了,输出:

我是module1中的Servce1中的m1方法

我是module2中的Servce1中的m2方法

猜你喜欢

转载自blog.csdn.net/weixin_56644618/article/details/127625751
今日推荐