JavaWeb学习打卡-Day6-SpringBean管理、SpringBoot自动装配、Maven高级
Spring Bean 的管理
获取Bean
- 默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
- 根据name获取bean:
Object getBean(String name)
- 根据类型获取bean:
<T> T getBean(Class<T> requiredType)
- 根据name获取bean(带类型转换):
<T> T getBean(String name, Class<T> requiredType)
@Autowired private ApplicationContext applicationContext;//IOC容器对象@Test public void testGetBean(){//根据bean的名称获取DeptController bean1 =(DeptController) applicationContext.getBean("deptController");System.out.println(bean1);//根据bean的类型获取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);//根据bean的名称及类型获取DeptController bean3 = applicationContext.getBean("deptcontroller",Deptcontroller.class);System.out.println(bean3); }
- 根据name获取bean:
- 上述所说的“Spring项目启动时,会把其中的bean都创建好”是主要针对于默认的单例非延迟加载的bean而言的,还会受到作用域及延迟初始化影响。
Bean作用域
- Spring中bean支持5种作用域,后三种在web环境才生效:
- singleton:容器内同名称的 bean 只有一个实例(单例)(默认)
- prototype:每次使用该 bean 时会创建新的实例(非单例)
- request:每个请求范围内会创建新的实例(web环境中,了解)
- session:每个会话范围内会创建新的实例(web环境中,了解)
- application:每个应用范围内会创建新的实例(web环境中,了解)
- 配置 bean 的作用域:
- 可以通过
@Scope
注解来配置作用域:@Scope("prototype")
。 - xml 方式:
<bean id="..." class="..." scope="singleton"></bean>
。
- 可以通过
- 注意:
- 默认singleton的bean,在容器启动时被创建,可以使用
@Lazy
注解来延迟初始化(延迟到第一次使用时)。 - prototype的bean,每一次使用该bean的时候都会创建一个新的实例。
- 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
- 默认singleton的bean,在容器启动时被创建,可以使用
第三方Bean
- 如果要管理的bean对象来自于第三方(不是自定义的),是无法用
@Component
及衍生注解声明bean的,就需要用到@Bean
注解。 - 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过
@Configuration
注解声明一个配置类。@Configuration public class CommonConfig{@Beanpublic SAXReader saxReader(){return new SAXReader();} }
- 通过
@Bean
注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。 - 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
@Component 和 @Bean
- 在 Java Spring 框架中,
@Component
和@Bean
都用于将对象注册到 Spring 容器中,但它们的应用场景和实现方式有显著区别。维度 @Component @Bean 作用对象 面向类 面向方法 控制权 隐式控制:由 Spring 自动实例化和管理 Bean 显式控制:开发者通过方法逻辑完全控制 Bean 的创建过程 Bean 名称 默认使用类名首字母小写(如 userService) 默认使用方法名,或通过 @Bean(name = “myBean”) 指定 依赖关系 自动扫描(需启用组件扫描 @ComponentScan) 显式定义在 @Configuration 类中,手动控制实例化逻辑 使用场景 自己编写的类 注册第三方库的类
Spring Boot 配置优先级
- 由低到高:
- application.yaml(忽略)
- application.yml
- application.properties
- java系统属性(-Dxxx=xxx)
- 命令行参数(–xxx=xxx)
Spring Boot 自动装配原理
Spring Boot 的自动配置就是当Spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
自动装配方案
@ComponentScan
组件扫描(繁琐,不推荐)@ComponentScan({"com.example","com.itheima","com.alibaba","com.google","org.springframework","org.mybatis",...}) @SpringBootApplication public class SpringbootWebconfig2Application{ }
@lmport
导入。使用@lmport
可以导入普通类、配置类、以及ImportSelector 接口实现类。导入的类会被Spring加载到IOC容器中。@Import({TokenParser.class, HeaderConfig.class}) @SpringBootApplication public class SpringbootWebConfig2Application{ }
@Enablexxx
注解。该注解封装了@Import
注解,方便,优雅。
Spring Boot 是如何实现自动装配的?
- SpringBoot 的核心注解
@SpringBootApplication
,该注解标注在SpringBoot工程引导类上。@SpringBootConfiguration
:允许在上下文中注册额外的 bean 或导入其他配置类,与@Configuration
作用相同。@ComponentScan
:默认会扫描启动类所在的包及其子包下所有的类 ,可以自定义不扫描某些 bean。@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制,是实现自动化配置的核心注解。
@EnableAutoConfiguration
只是一个简单的注解,底层封装了@Import(AutoConfigurationImportselector.class)
注解。- 自动装配核心功能的实现实际是通过
AutoConfigurationImportSelector
类。 AutoConfigurationImportSelector
类实现了ImportSelector
接口,也就实现了这个接口中的selectImports
方法,该方法主要用于获取所有符合条件的类的全限定类名,返回的String[]种这些类需要被加载到 IOC 容器中。- 具体读取META-INF/spring.factories,获取需要自动装配的所有配置类。
- Spring Boot会根据
@ConditionalOnXXX
注解条件装配。
- 自动装配核心功能的实现实际是通过
总结:Spring Boot 通过
@EnableAutoConfiguration
开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖。
Maven 高级
分模块开发
- 将项目按照功能拆分成若干个子模块,方便项目的管理维护、扩展,也方便模块间的相互调用,资源共享。
- 分模块开发需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分。
Maven 继承
- 概念:继承描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承。
- 作用:可以将公共依赖定义在父工程中,从而简化依赖配置、统一管理依赖。
- 实现:
<parent>...</parent>
- 创建 maven 模块 tlias-parent,该工程为父工程,设置打包方式pom(默认jar)。
<packaging>pom</packaging>
jar:普通模块打包,springboot项目基本都是jar包(内嵌tomcat运行)。
war:普通web程序打包,需要部署在外部的tomcat服务器中运行。
pom:父工程或聚合工程,该模块不写代码,仅进行依赖管理。 - 在子工程的pom.xml文件中配置继承关系。
在子工程中配置了继承关系之后,其坐标中的groupId是可以省略的,因为会自动继承父工程的。
relativePath标签指定父工程的pom文件的相对位置(如果不指定,将从本地仓库/远程仓库查找该工程)。 - 在父工程中配置各个工程共有的依赖(子工程会自动继承父工程的依赖)。
若父子工程都配置了同一个依赖的不同版本,以子工程的为准。
- 创建 maven 模块 tlias-parent,该工程为父工程,设置打包方式pom(默认jar)。
版本锁定
- 可以在父工程的pom文件中通过
<dependencyManagement>
来统一管理依赖版本。 - 子工程引入依赖时,无需指定
<version>
版本号,父工程统一管理。变更依赖版本只需在父工程中统一变更。<dependencies>
是直接依赖,在父工程配置了依赖,子工程会直接继承下来。
<dependencyanagement>
是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)。 - 还可以通过自定义属性集中管理版本号。
Maven 聚合
- 聚合:将多个模块组织成一个整体,同时进行项目的构建。
- 聚合工程:一个不具有业务功能的“空”工程(有且仅有一个pom文件)。
- 作用:快速构建项目(无需根据依赖关系手动构建,直接在聚合工程上构建即可)。
- 实现:通过
<modules>
设置当前聚合工程所包含的子模块名称。聚合工程中所包含的模块在构建时,会自动根据模块间的依赖关系设置构建顺序,与聚合工程中模块的配置书写位置无关。<modules><module>../tlias-pojo</module><module>../tlias-utils</module><module>../tlias-web-management</module> </modules>
Maven 继承与聚合
- 作用:
- 聚合用于快速构建项目。
- 继承用于简化依赖配置、统一管理依赖。
- 相同点:
- 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中。
- 聚合与继承均属于设计型模块,并无实际的模块内容。
- 不同点:
- 聚合是在聚合工程中配置关系,聚合可以感知到参与聚合的模块有哪些。
- 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己。