【小家Spring】如何证明Spring是存在父子容器的?顺便解决Spring MVC访问一直404问题(配置文件没问题)(上)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】如何证明Spring是存在父子容器的?顺便解决Spring MVC访问一直404问题(配置文件没问题)(上)

前言


各位老铁们是否遇曾经遇到过这样的疑惑:同样是Spring容器里的Bean,为何能够@Autowireservice进Controller里面,但是反之注入就报错呢?报找不到bean~


但是自己从容器里明明可以拿到这个Bean啊,怎么回事呢?

同样的我们发现,容器里面的属性值,容器之间也是不互通的?


环境准备



准备一个传统的Spring环境(注意,一定不能是Spring Boot环境),为了偷懒,项目环境各位移步此处:

【小家Spring】Spring注解驱动开发—Servlet 3.0整合Spring MVC(不使用web.xml部署描述符,全注解驱动)


如何证明Spring是存在父子容器的


我们现在的结论是,在Web环境中,是分为SpringMvc管理的子容器,和Spring管理的父容器。如何证明呢?


基于上面的项目环境(请参看项目环境,因为如果项目环境不对,得到的效果可能会被误导的,总之就是保证@Controller只被扫描一次)


我们分别让Controller和Service实现ApplicationContextAware,就可以证明出:


image.png


结论,虽然类型AnnotationConfigWebApplicationContext:但是显然是不一样的,从它从写的toString()方法里可以看出:


  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder(getDisplayName());
    sb.append(": startup date [").append(new Date(getStartupDate()));
    sb.append("]; ");
    ApplicationContext parent = getParent();
    if (parent == null) {
      sb.append("root of context hierarchy");
    }
    else {
      sb.append("parent: ").append(parent.getDisplayName());
    }
    return sb.toString();
  }


==============备注:说一下Spring Boot环境下的:

结果我们发现(各位自己去试验哈),使用的是一模一样的(这里指的一模一样,就是一个,地址值都是一样的)AnnotationConfigEmbeddedWebApplicationContext,可以看出在boot环境中使用的是相同的容器管理的(无父子容器概念)。备注:该类在org.springframework.boot.context.embedded中这个包里面,属于Boot后来自己实现的


附上一个继承图谱:

image.png


注意:


我们的ApplicationContext以及BeanFactory都是可以直接@Autowired的,如下:

Controller注入:
    @Autowired
    private ApplicationContext applicationContext; WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Mar 07 15:25:04 CST 2019]; parent: Root 
    @Autowired
    private BeanFactory beanFactory; // org.springframework.beans.factory.support.DefaultListableBeanFactory@41b6d6b3: defining beans [...
Service注入:
    @Autowired
    private ApplicationContext applicationContext; //Root WebApplicationContext: startup date [Thu Mar 07 15:25:02 CST 2019]; root of context hierarchy
    @Autowired
    private BeanFactory beanFactory; //rg.springframework.beans.factory.support.DefaultListableBeanFactory@747a2296: defining beans [...


由此可以看出,容器直接注入进来就行。但是,但是,但是如果存在父子容器的话,在不同的层,注入的对象也是不一样的,这点在了解了Spring容器的机制的情况下,是很好理解的~~~

如何证明Spring的父容器不能访问子容器的Bean


其实这个在上面的那篇博文里已经举例了。

比如,我在Web子容器的配置文件里注册一个Bean:

@ComponentScan(value = "com.fsx", useDefaultFilters = false,
        includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}
)
@Configuration
public class AppConfig {
    @Bean
    public Child child() {
        return new Child();
    }
}


然后在Spring管理的Root父容器里注册一个Bean:


@ComponentScan(value = "com.fsx", excludeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        //排除掉web容器的配置文件,否则会重复扫描
        @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {AppConfig.class})
})
@Configuration
public class RootConfig {
    @Bean
    public Parent parent() {
        return new Parent();
    }
}


然后我们先在Controller里面注入这两个Bean,如下:


@Controller
@RequestMapping("/controller")
public class HelloController implements ApplicationContextAware {
    @Autowired
    private HelloService helloService;
    @Autowired
    private Parent parent;
    @Autowired
    private Child child;
    @ResponseBody
    @GetMapping("/hello")
    public String helloGet() {
        System.out.println(parent);
        System.out.println(child);
        System.out.println(helloService);
        System.out.println(helloService.hello());
        return "hello...Get";
    }
}

启动,访问。我们发现一切正常,并且都有值。


现在我在Service里注入这两个类如下:


@Service
public class HelloServiceImpl implements HelloService, ApplicationContextAware {
    @Autowired
    private Parent parent;
    @Autowired
    private Child child;
    @Override
    public Object hello() {
        System.out.println(parent);
        System.out.println(child);
        return "service hello";
    }
}

启动项目,我们就发现报错了,找不到Child这和Bean.


从上面这个例子,就可以看出。子容器是可以访问父容器里的Bean的,但是父容器不能访问子容器内的Bean。所以很显然,直接向Service里面@Autowire一个Controller,启动时候也是会报错的~


另外可以说一点,父子容器的初始化顺序为:先父容器,再子容器。所以web组件一般都是最后被初始化的(当然还存在循环嵌套的情况,另当别论了)。因为若使用web.xml配置Spring容器,是先执行ContextLoaderListener#contextInitialized启动Spring容器,再初始化DispatcherServlet来启动web容器的

相关文章
|
4月前
|
Java Spring
Spring boot 运行服务jar外配置配置文件方式总结
Spring boot 运行服务jar外配置配置文件方式总结
927 0
|
1月前
|
XML Java 数据格式
Spring从入门到入土(xml配置文件的基础使用方式)
本文详细介绍了Spring框架中XML配置文件的使用方法,包括读取配置文件、创建带参数的构造对象、使用工厂方法和静态方法创建对象、对象生命周期管理以及单例和多例模式的测试。
85 7
Spring从入门到入土(xml配置文件的基础使用方式)
|
24天前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
1月前
|
Java 测试技术 Spring
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
这篇文章介绍了Spring Boot中配置文件的语法、如何读取配置文件以及如何通过静态工具类读取配置文件。
49 0
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
|
2月前
|
消息中间件 NoSQL 安全
(转)Spring Boot加载 不同位置的 application.properties配置文件顺序规则
这篇文章介绍了Spring Boot加载配置文件的顺序规则,包括不同位置的application.properties文件的加载优先级,以及如何通过命令行参数或环境变量来指定配置文件的名称和位置。
|
3月前
|
Java Spring 传感器
AI 浪潮席卷,Spring 框架配置文件管理与环境感知,为软件稳定护航,你还在等什么?
【8月更文挑战第31天】在软件开发中,配置文件管理至关重要。Spring框架提供强大支持,便于应对不同环境需求,如电商项目的开发、测试与生产环境。它支持多种格式的配置文件(如properties和YAML),并能根据环境加载不同配置,如数据库连接信息。通过`@Profile`注解可指定特定环境下的配置生效,同时支持通过命令行参数或环境变量覆盖配置值,确保应用稳定性和可靠性。
62 0
|
4月前
|
前端开发 Java 应用服务中间件
我以为我对Spring MVC很了解,直到我遇到了...
所有人都知道Spring MVC是是开发的,却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子,他就是Trygve Mikkjel Heyerdahl Reenskaug,挪威计算机科学家,名誉教授。Trygve Reenskaug的MVC架构思想早期用于图形用户界面(GUI) 的软件设计,他对MVC是这样解释的。MVC 被认为是解决用户控制大型复杂数据集问题的通用解决方案。最困难的部分是为不同的架构组件想出好的名字。模型-视图-编辑器是第一个。
127 1
我以为我对Spring MVC很了解,直到我遇到了...
|
3月前
|
XML Java 数据库连接
深入解析 Spring 配置文件:从基础到高级
【8月更文挑战第3天】Spring配置文件是构建与管理Spring应用的核心,它涵盖了从基础到高级的各种配置技巧。基础配置采用`.xml`格式定义Bean及其依赖;中级配置包括设置Bean作用域及引入属性文件;高级配置则涉及AOP、事务管理和与其他框架的整合。熟练掌握这些配置能帮助开发者构建出更为灵活且易维护的应用系统。
|
4月前
|
存储 安全 Java
Spring Boot中的配置文件加密
Spring Boot中的配置文件加密
|
4月前
|
XML 前端开发 Java
Spring Boot与Spring MVC的区别和联系
Spring Boot与Spring MVC的区别和联系