【笔记】Spring IoC

Spring的核心就是提供了一个IoC容器,它可以管理所有轻量级的JavaBean组件,提供的底层服务包括组件的生命周期管理、配置和组装服务、AOP支持,以及建立在AOP基础上的声明式事务服务等。

核心问题是:

  1. 谁负责创建组件?
  2. 谁负责根据依赖关系组装组件?
  3. 销毁时,如何按依赖顺序正确销毁?

在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实际上是这个FactoryBeangetObject()方法返回的Bean。为了和普通Bean区分,我们通常都以XxxFactoryBean命名。

Resource 类

Spring提供了一个org.springframework.core.io.Resource(注意不是javax.annotation.Resource),它可以像Stringint一样使用@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

主要来源:https://www.liaoxuefeng.com/wiki/1252599548343744

posted @ 2021-08-19 20:22  KiritoUzumaki  阅读(49)  评论(0)    收藏  举报