【笔记】Spring IoC
Spring的核心就是提供了一个IoC容器,它可以管理所有轻量级的JavaBean组件,提供的底层服务包括组件的生命周期管理、配置和组装服务、AOP支持,以及建立在AOP基础上的声明式事务服务等。
核心问题是:
- 谁负责创建组件?
- 谁负责根据依赖关系组装组件?
- 销毁时,如何按依赖顺序正确销毁?
在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件
IoC又称为依赖注入(DI:Dependency Injection),它解决了一个最主要的问题:将组件的创建+配置与组件的使用相分离,并且,由IoC容器负责管理组件的生命周期。因为IoC容器要负责实例化所有的组件,因此,有必要告诉容器如何创建组件,以及各组件的依赖关系。
注入方式
- 属性
- 构造器
POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
<spring.version>5.2.3.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
Bean 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.itranswarp.learnjava.service.UserService">
<property name="mailService" ref="mailService" />
</bean>
<bean id="mailService" class="com.itranswarp.learnjava.service.MailService" />
</beans>
- 每个
<bean ...>都有一个id标识,相当于Bean的唯一ID; - 在
userServiceBean中,通过<property name="..." ref="..." />注入了另一个Bean; - Bean的顺序不重要,Spring根据依赖关系会自动正确初始化。
ApplicationContext
- ClassPathXmlApplicationContext
- AnnotationConfigApplicationContext
BeanFactory 是 ApplicationContext 的爹,青出于蓝
开启注解扫描
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example.spring"
/>
</beans>
Annotation
- @Component
- @ComponentScan
- @Configuration
- @Autowried
Scope
Singleton : 在容器初始化时创建Bean ,容器关闭时销毁Bean
Prototype:每次getBean时,容器都返回一个新的实例
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // @Scope("prototype")
注入List,List<T> T 为爹,可以批量注入儿子们
- 设计时,存在多个实现类,单独调用时需要指明bean_name
@Order,指定注入list时的访问顺序
非必要的注入,在@Autowired增加一个required = false
创建第三方Bean,单例
@Configuration
@ComponentScan
public class AppConfig {
// 创建一个Bean:
@Bean
ZoneId createZoneId() {
return ZoneId.of("Z");
}
}
初始化和销毁
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
在Bean的初始化和清理方法上标记@PostConstruct和@PreDestroy:
别名
出现重复的bean 命名,
- 使用
@Bean("name")指定别名 - 也可以用
@Bean+@Qualifier("name")指定别名。
注入时需要指定相对应的别名。注入标记有@Primary的Bean,通常定义为主数据源,默认注入主数据源
FactoryBean
当一个Bean实现了FactoryBean接口后,Spring会先实例化这个工厂,然后调用getObject()创建真正的Bean。getObjectType()可以指定创建的Bean的类型,因为指定类型不一定与实际类型一致,可以是接口或抽象类。
因此,如果定义了一个FactoryBean,要注意Spring创建的Bean实际上是这个FactoryBean的getObject()方法返回的Bean。为了和普通Bean区分,我们通常都以XxxFactoryBean命名。
Resource 类
Spring提供了一个org.springframework.core.io.Resource(注意不是javax.annotation.Resource),它可以像String、int一样使用@Value注入
注入配置
Spring容器提供 @PropertySource来自动读取配置文件
Spring容器看到@PropertySource("app.properties")注解后,自动读取这个配置文件,然后,我们使用@Value正常注入
@Configuration
@ComponentScan
@PropertySource("app.properties") // 表示读取classpath的app.properties
public class AppConfig {
@Value("${app.zone:Z}")
String zoneId;
@Bean
ZoneId createZoneId() {
return ZoneId.of(zoneId);
}
}
注意注入的字符串语法,它的格式如下:
"${app.zone}"表示读取key为app.zone的value,如果key不存在,启动将报错;"${app.zone:Z}"表示读取key为app.zone的value,但如果key不存在,就使用默认值Z
JavaBean持有所有的配置
@Component
public class SmtpConfig {
@Value("${smtp.host}")
private String host;
@Value("${smtp.port:25}")
private int port;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
}
使用#{} 的语法读取javabean 配置
@Componentpublic class MailService { @Value("#{smtpConfig.host}") private String smtpHost; @Value("#{smtpConfig.port}") private int smtpPort;}
条件装配
根据不同的开发环境来决定所使用的配置
- @Profile
- @Conditional

浙公网安备 33010602011771号