夯实spring(二十三): 父子容器

本文要点:

  1. 什么是父子容器
  2. 为什么需要用父子容器
  3. 父子容器如何使用

先来一个案例

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

模块1

module1.service1

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

module1.service2

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Service2 {
    @Autowired
    private Service1 service1; 
    public String m1() {
        return this.service1.m1();
    }
}

module1.Module1Config

import org.springframework.context.annotation.ComponentScan;
//会自动扫描当前类所在的包中的所有类,将标注有@Compontent注解的类注册到spring容器,即Service1和Service2会被注册到spring容器。
@ComponentScan
public class Module1Config {
}

模块2

module2.Service1

import org.springframework.stereotype.Component;
@Component
public class Service1 {
    public String m2() {
        return "我是module2中的Servce1中的m2方法";
    }
}

module2.Service3

import com.javacode2018.lesson002.demo17.module1.Service2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Service3 {
    //使用模块2中的Service1
    @Autowired
    private module2.Service1 service1;
    //使用模块1中的Service2
    @Autowired
    private module1.Service2 service2;
    
    public String m1() {
        return this.service2.m1();
    }
    public String m2() {
        return this.service1.m2();
    }
}

module2.Module2Config

@ComponentScan
public class Module2Config {
}

上面的这些使用spring来操作是会有问题的

会报错,因为两个模块中都有Service1,被注册到spring容器的时候,bean名称会冲突,导致注册失败。

运行看一下

public class ParentFactoryTest {
    @Test
    public void test1() {
        //定义容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册bean
        context.register(Module1Config.class, Module2Config.class);
        //启动容器
        context.refresh();
    }
}

Caused by:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name ‘service1’ for bean class
[module2.Service1] conflicts with existing, non-compatible bean
definition of same name and class [module1.Service1]

我们可以使用spring中的父子容器就可以很好的解决上面这种问题。

什么是父子容器

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

方式1:BeanFactory的方式

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

方式2:ApplicationContext的方式

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

父子容器特点

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

使用父子容器解决上面的问题

@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方法

springmvc的父子容器

springmvc父子容器就是controller层交给一个spring容器加载,其他的service和dao层交给另外一个spring容器加载,这两个容器组成了父子容器的关系

  • springmvc中只使用一个容器是可以正常运行的。
  • 通常我们使用springmvc的时候,采用3层结构,controller层,service层,dao层;父容器中会包含dao层和service层,而子容器中包含的只有controller层;这2个容器组成了父子容器的关系,controller层通常会注入service层的bean。
  • 采用父子容器可以避免有些人在service层去注入controller层的bean,导致整个依赖层次是比较混乱的。

父容器和子容器的需求也是不一样的,比如父容器中需要有事务的支持,会注入一些支持事务的扩展组件,而子容器中controller完全用不到这些,对这些并不关心,子容器中需要注入一下springmvc相关的bean,而这些bean父容器中同样是不会用到的,也是不关心一些东西,将这些相互不关心的东西隔开,可以有效的避免一些不必要的错误,而父子容器加载的速度也会快一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值