129.【Spring 注解 IOC】

Spring 注解

  • (一)、组件注册
    • 1. @Configuration 与 @Bean 容器注册组件
        • (1).无注解注入方式
        • (2).注解注入方式
    • 2. @ComponentScan 自动扫描组件和自动扫描规则
        • (1).无注解扫描方式
        • (2).注解扫描注入方式
        • (3).指定扫描或不扫描的包 (过滤)
    • 3. 自定义TypeFilter指定过滤规则 @Filter
        • (1).自定义我们的扫描过滤器
    • 4.设置组件的作用域 @Scope
        • (1).组件默认是单实列
        • (2).修改为多实列 (注解)
        • (3).使用我们的XML文件进行实现多实列
    • 5.@Layz-bean懒加载
        • (1).懒加载
    • 6.@Conditional 按照条件注册bean
        • (1).按照一定的条件进行注册bean
    • 7.@Import给容器中快速导入一个组件
        • (1).@Import
        • (2).ImportSelector ⭐
        • (3). ImportBeanDefinitionRegistrar
        • (4).FactoryBean
  • (二)、组件的生命周期
    • 1.@Bean指定初始化和销毁方法
        • (1). 使用配置文件进行自定义我们的初始化方法和销毁方法 (==第一种==)
        • (2).通过@Bean注解进行初始化和销毁 (==第二种==)
    • 2.InitializingBean与 DisposableBean 进行初始化和销毁 (==第三种==)
        • (1).通过实现接口进行初始化和销毁的操作
    • 3.使用JSR250规范 (==第四种==)
        • (1).@PostConstruct 和 @PreDestroy
    • 4.BeanPostProcessor后置处理器 (==第五种==)
        • (1).BeanPostProcessor 后置处理器
    • 5.Spring底层对BeanPostProcessor的使用
        • (1). 【案例1】在实体类中获取ioc容器
  • (三)、属性赋值相关的注解
    • 1.@Value
        • (1).普通属性赋值 和 SPEL表达式赋值
    • 2. @PropertySource 加载外部配置文件
        • (1).使用配置文件的方式加载外部文件
        • (2).使用注解的方式 加载外部文件
  • (四)、自动装配
    • 1.@Autowired 自动装配
        • (1). 自动装配(原理是从IOC容器中获得值并赋值)
        • (2).@AutoWried(先类型后属性名)
        • (3).@Qualifier 配合 @AutoWried
        • (4).@Primary 首选装配
    • 2.@Resource 和 @Inject [JSR标准]
        • (1).@Resource 自动装配
        • (2).@Inject 自动装配
    • 3.@Autowried自动装配原理
        • (1).标注在Set方法位置上
        • (2).标注在有参构造方法上
        • (3).@Bean + 方法参数
    • 4.自定义组件使用Spring容器底层的一些组件
        • (1).xxxAware
    • 5.@Profile 切换多个应用场景
        • (1). 环境搭建
        • (2).根据环境注册bean (环境切换)

在这里插入图片描述

(一)、组件注册

1. @Configuration 与 @Bean 容器注册组件

(1).无注解注入方式

  1. 在pom文件中加入spring-context依赖
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.12.RELEASE</version>
</dependency>
  1. 定义一个实体类
package com.jsxs.bean;

/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {

    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

  1. 在resource目录下的beans.xml配置文件中通过< bean>< /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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--  通过Bean的方式进行我们的组件注入的操作  -->
    <bean id="person" class="com.jsxs.bean.Person">
        <property name="name" value="李明"></property>
        <property name="age" value="19"></property>
    </bean>
</beans>
  1. 获取容器中通过配置文件注入的实例对象
package com.jsxs;

import com.jsxs.bean.Person;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/11 20:14
 * @PackageName:com.jsxs
 * @ClassName: MainTest
 * @Description: TODO
 * @Version 1.0
 */
public class MainTest {
    public static void main(String[] args) {

        // 通过配置文件,创建ioc容器,并向容器中注入实列对象
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        // 根据bean的id获取容器中注入的实列对象
        Person person = (Person)applicationContext.getBean("person");
        System.out.println(person);

    }
}

在这里插入图片描述

(2).注解注入方式

1.MyConfig.java

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */

@Configuration
public class MyConfig {

    @Bean
    public Person person(){
        return new Person("李三",21);
    }
}

2.Main.java

package com.jsxs;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:07
 * @PackageName:com.jsxs
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
    	// 读取通过配置类,创建ioc容器,并向容器中注入实例对象
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        Person person = (Person)applicationContext.getBean("person");
        System.out.println(person);
    }
}

在这里插入图片描述

2. @ComponentScan 自动扫描组件和自动扫描规则

(1).无注解扫描方式

只要我们加上 @Configuration 这个注解,这个类就会默认加入IOC容器。

  1. 设置三个组件,并通过包扫描的方式进行注入我们的容器。
package com.jsxs.Mapper;

import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
@Repository
public class BookMapper {
}

package com.jsxs.service;

import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

}

package com.jsxs.controller;

import org.springframework.stereotype.Controller;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.controller
 * @ClassName: BookController
 * @Description: TODO
 * @Version 1.0
 */
@Controller
public class BookController {
}

1. beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 包自动扫描: 凡是带有 @Controller @Service @Repository @Component     -->
    <context:component-scan base-package="com.jsxs"/>
    <!--  通过Bean的方式进行我们的组件注入的操作  -->
    <bean id="person" class="com.jsxs.bean.Person">
        <property name="name" value="李明"/>
        <property name="age" value="19"/>
    </bean>

</beans>

2.IOCTest.java

package com.jsxs.Test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest {
    public static void main(String[] args) {
        // 读取通过配置文件注入容器中实列
        ClassPathXmlApplicationContext applicationContext = new   ClassPathXmlApplicationContext("beans.xml");
        // 进行遍历的操作
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

(2).注解扫描注入方式

MyConfig.java 带有@Configuration的注解一开始就会被默认加入我们的组件中去。

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */
@ComponentScan(value = "com.jsxs")
@Configuration
public class MyConfig {

    @Bean
    public Person person(){
        return new Person("李三",21);
    }
}

在这里插入图片描述

(3).指定扫描或不扫描的包 (过滤)

  1. 使用 @ComponentScan 进行操作扫描包 - (排除xxx)
package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */

// 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
@ComponentScan(value = "com.jsxs",
        excludeFilters = {  // 这里是排除掉xxx
                @ComponentScan.Filter(
                        type = FilterType.ANNOTATION,
                        classes = {
                                Controller.class,
                                Service.class
                        }
                )
        })
@Configuration
public class MyConfig {

    @Bean
    public Person person() {
        return new Person("李三", 21);
    }
}

结果我们发现: 我们IOC容器中的组件中少我们指定的Controller 和 Service 这两个组件标注的组件
在这里插入图片描述

  1. 使用 @ComponentScans 进行扫描多个 @ComponentScan (不排除xxx)
package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */

// 这里可以通过 @ComponentScans 配置多个 @@ComponentScan
    @ComponentScans(value = {
// 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
            @ComponentScan(value = "com.jsxs",
                    includeFilters = {  // 这里是只有包含这些组件的才被打印出来
                            @ComponentScan.Filter(
                                    type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}
                            )}, useDefaultFilters = false)  // 这里就相当于把所有的非includeFilters全部过滤掉,不显示(默认为true)
    })

@Configuration
public class MyConfig {

    @Bean
    public Person person() {
        return new Person("李三", 21);
    }
}

我们发现我们的结果 只有我们通过配置
在这里插入图片描述

3. 自定义TypeFilter指定过滤规则 @Filter

(1).自定义我们的扫描过滤器

在这里插入图片描述
1. 过滤的文件是这样写的

package com.jsxs.config;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**
 * @Author Jsxs
 * @Date 2023/8/12 19:57
 * @PackageName:com.jsxs.config
 * @ClassName: MyTypeFilter
 * @Description: TODO  自定义过滤的话,我们需要实现这个 TypeFilter 接口
 * @Version 1.0
 */
public class MyTypeFilter implements TypeFilter { //⭐
    /**
     *
     * @param metadataReader  : 读取当前正在扫描的类
     * @param metadataReaderFactory : 可以获取到其他任何类的信息
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
         // 1.获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // 2.获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // 3.获取当前类资源(类路径)
        Resource resource = metadataReader.getResource();
         // 4.获取当前类的类名
        String className = classMetadata.getClassName();
        System.out.println("---> "+className);
        // 5.假如 类名中存在 er 的话,我们就将这个容器注入到组件中去
        if (className.contains("er")){
            return true;
        }
        return false;
    }
}

2. 配置文件是这样写的

package com.jsxs.config;

import com.jsxs.Mapper.BookMapper;
import com.jsxs.bean.Person;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */

/**
 *  TODO: 1. ANNOTATION 按照注解 ; 2.  ASSIGNABLE_TYPE 按照给定的类型 3.CUSTOM 自定义规则
 */
// 1. 这里是一个数组,可以包含多个@ComponentScan
@ComponentScans(value = {
        //  2. 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
        @ComponentScan(value = "com.jsxs",
                // 3. 这里是一个数组,可以包含多个 Filter
                includeFilters = {  // 4. 这里是只有包含这些组件的才被打印出来
                        // 4.1 第一个Filter ⭐
                        @ComponentScan.Filter( // 5. 类型是注解 ; 要过滤的类文件
                                type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}
                        ),
                        // 4.2 第二个Filter ⭐
                        @ComponentScan.Filter(
                                type = FilterType.ASSIGNABLE_TYPE,classes = {BookMapper.class}
                        ),
                        // 4.3 第三个Filter ⭐
                        @ComponentScan.Filter(  // 5.指向我们自定义的过滤类信息
                                type = FilterType.CUSTOM,classes = {MyTypeFilter.class}
                        )
                }, useDefaultFilters = false)  // 这里就相当于把所有的非includeFilters全部过滤掉,不显示

})
@Configuration
public class MyConfig {

    @Bean
    public Person person() {
        return new Person("李三", 21);
    }
}

在这里插入图片描述

4.设置组件的作用域 @Scope

(1).组件默认是单实列

组件默认在IOC容器中是单实列的,也就是说我们在IOC容器中使用的组件都是同一个组件。
1. 进行编写我们的配置文件

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {

    @Bean("person2")
    public Person person(){
        return new Person("张三2",22);
    }
}

2.测试类

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.通过我们的组件名获取我们指定的组件信息
        Person person = (Person)applicationContext.getBean("person2");
        Person person2 = (Person)applicationContext.getBean("person2");
        // 3.打印出我们的组件信息
        System.out.println(person);
        // 4.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件
        System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
    }
}

在这里插入图片描述

(2).修改为多实列 (注解)

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {

    /**  1. singleton 但是列的
     *   2.prototype 多实列   (默认值)
     *   3. 同一次请求创建一个实列
     *   4. 同一个session创建一个实列
     */
    @Scope(value = "prototype")  // ⭐ 我们这在里修改为多实列的
    @Bean("person2")
    public Person person(){
        return new Person("张三2",22);
    }
}

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.通过我们的组件名获取我们指定的组件信息
        Person person = (Person)applicationContext.getBean("person2");
        Person person2 = (Person)applicationContext.getBean("person2");
        // 3.打印出我们的组件信息
        System.out.println(person);
        // 4.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件  ⭐
        System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
    }
}

在这里插入图片描述

(3).使用我们的XML文件进行实现多实列

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<!--     包自动扫描: 凡是带有 @Controller @Service @Repository @Component     -->
    <context:component-scan base-package="com.jsxs"/>
    <!--  通过Bean的方式进行我们的组件注入的操作  -->
    <bean id="person" class="com.jsxs.bean.Person" scope="prototype">
        <property name="name" value="李明"/>
        <property name="age" value="19"/>
    </bean>

</beans>

在这里插入图片描述
小结: 我们使用多实列的情况下,我们的组件并不会在IOC创建完成的时候进创建我们的实列,而是当我们使用到组件的时候,才会帮助我们创建我们的实列。 (懒汉式)

单实列: 我们的组件会在我们的容器创建完成之后就会帮助我们创建我们的实列。 (饿汉式)

5.@Layz-bean懒加载

(1).懒加载

单实例bean,默认在容器创建启动的时候就会创建对象。但是在懒加载模式下,容器启动的时候不会创建对象,而是在第一次使用(获取)Bean的时候才会创建并初始化。

单实列 + 懒加载 ≠ 多实例
1. 设置配置类的组件为 单实列+懒加载

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {

    /**  1. singleton 但是列的
     *   2.prototype 多实列   (默认值)
     *   3. 同一次请求创建一个实列
     *   4. 同一个session创建一个实列
     */
    @Scope(value = "prototype")  //⭐
    @Bean("person2")
    @Lazy  //⭐
    public Person person(){
        return new Person("张三2",22);
    }
}

2.进行测试

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.通过我们的组件名获取我们指定的组件信息
        Person person = (Person)applicationContext.getBean("person2");
        Person person2 = (Person)applicationContext.getBean("person2");
        // 3.打印出我们的组件信息
        System.out.println(person);
        // 4.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件
        System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
    }
}

因为懒加载的意思就是当我们使用的时候才回去创建实列,又因为是单实列的所以我们只会创建一次
在这里插入图片描述

6.@Conditional 按照条件注册bean

(1).按照一定的条件进行注册bean

按照一定的条件进行判断,满足条件时才给容器中注册bean。

这里我们要实现 condition 的接口,因为我们的@Conditional({参数}),这里的参数就是我们需要继承 condition 的接口。
WindowConditional.java

package com.jsxs.conditional;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @Author Jsxs
 * @Date 2023/8/13 19:18
 * @PackageName:com.jsxs.conditional
 * @ClassName: WindowConditional
 * @Description: TODO
 * @Version 1.0
 */
public class WindowConditional implements Condition {  //⭐

    /**
     *
     * @param context : 可以获取到上下文
     * @param metadata : 注解
     * @return
     */

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        if (environment.getProperty("os.name").contains("Windows")){
            return true;
        }
        return false;
    }
}

LinuxConditional.java

package com.jsxs.conditional;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @Author Jsxs
 * @Date 2023/8/13 19:18
 * @PackageName:com.jsxs.conditional
 * @ClassName: LinuxConditional
 * @Description: TODO  我们需要继承Condition这个接口
 * @Version 1.0
 */
public class LinuxConditional implements Condition {  //⭐
    /**
     *
     * @param context : 判断条件能使用的上下文(环境)
     * @param metadata : 注释信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        // 1. 能获取到IOC使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 2. 能获取到类加载器
        ClassLoader classLoader = context.getClassLoader();
        // 3. 获取我们的开发环境
        Environment environment = context.getEnvironment();
        // 4.获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        if (environment.getProperty("os.name").contains("Linux")){
            return true;
        }
        return false;
    }
}

MyConfig2.java

package com.jsxs.config;

import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {


    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})  //⭐
    @Bean("person01")
    public Person person01(){
        return new Person("张三01",33);
    }
    @Conditional(LinuxConditional.class)  // ⭐
    @Bean("person02")
    public Person person02(){
        return new Person("张三02",33);
    }
}

在这里插入图片描述

7.@Import给容器中快速导入一个组件

这个注解需要放在我们的配置类上,因为配置类项目刚启动的时候就会加载进组件,我们IOC需要识别到这个 @Import 才能继续工作。

    /**
     *  给容器中注册组件
     *  1. 包扫描 + 组件标注注解 (repository,service controller component)
     *  2. @Configuration + @Bean
     *  3. @Import[快速给容器导入一个组件]
     * 		(1).@Import(要导入的容器),容器中会自动注册这个组件,id默认是全限定名。
     * 		(2).@ImportSelector: 返回需要导入的组件的全限定名数组。
     *  4.FactoryBean: 使用Spring提供的FactoryBean (工厂Bean)
     */

(1).@Import

1.要注册的组件

package com.jsxs.bean;

/**
 * @Author Jsxs
 * @Date 2023/8/13 20:54
 * @PackageName:com.jsxs.bean
 * @ClassName: Color
 * @Description: TODO
 * @Version 1.0
 */
public class Color {
}

2.@Import注解放在类上

package com.jsxs.config;

import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
// 快速的导入组件,id默认的是全限定名 ⭐
@Import(Color.class)
public class MyConfig2 {

    /**
     * 1. singleton 但是列的
     * 2.prototype 多实列   (默认值)
     * 3. 同一次请求创建一个实列
     * 4. 同一个session创建一个实列
     */
    @Scope(value = "singleton")
    @Bean("person2")
    @Lazy
    public Person person() {
        return new Person("张三2", 22);
    }

    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})
    @Bean("person01")
    public Person person01() {
        return new Person("张三01", 33);
    }

    @Conditional(LinuxConditional.class)
    @Bean("person02")
    public Person person02() {
        return new Person("张三02", 33);
    }

}

3.测试

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getSystemEnvironment());
        // 3.获取我们具体的属性名
        System.out.println(environment.getProperty("os.name"));
        // 2.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

    }
}

在这里插入图片描述

(2).ImportSelector ⭐

假如我们的类实现了 ImportSelector 的接口,那么我们这个类的返回值就是我们需要注入IOC容器中组件的全限定名。.

在这里插入图片描述
1.MyImportSelector.java

package com.jsxs.conditional;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @Author Jsxs
 * @Date 2023/8/13 21:07
 * @PackageName:com.jsxs.conditional
 * @ClassName: MyImportSelector
 * @Description: TODO   自定义逻辑返回需要导入的组件
 * @Version 1.0
 */
public class MyImportSelector implements ImportSelector {

    /**
     *
     * @param importingClassMetadata :  当前标注@Import注解的类的所有注解信息
     * @return : 返回值就是导入容器中的组件全类名
     */

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        return new String[]{"com.jsxs.bean.Yellow","com.jsxs.bean.Red"};  // ⭐
    }
}

package com.jsxs.config;

import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.MyImportSelector;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
// 快速的导入组件,id默认的是全限定名   ⭐⭐
@Import({Color.class, MyImportSelector.class})

public class MyConfig2 {

    /**
     * 1. singleton 但是列的
     * 2.prototype 多实列   (默认值)
     * 3. 同一次请求创建一个实列
     * 4. 同一个session创建一个实列
     */
    @Scope(value = "singleton")
    @Bean("person2")
    @Lazy
    public Person person() {
        return new Person("张三2", 22);
    }

    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})
    @Bean("person01")
    public Person person01() {
        return new Person("张三01", 33);
    }

    @Conditional(LinuxConditional.class)
    @Bean("person02")
    public Person person02() {
        return new Person("张三02", 33);
    }

    /**
     *  给容器中注册组件
     *  1. 包扫描 + 组件标注注解 (repository,service controller component)
     *  2. @Configuration + @Bean
     *  3. @Import
     */
}

在这里插入图片描述

(3). ImportBeanDefinitionRegistrar

在这里插入图片描述
1.我们需要实现一个接口 ImportBeanDefinitionRegistrar

package com.jsxs.conditional;

import com.jsxs.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @Author Jsxs
 * @Date 2023/8/14 8:44
 * @PackageName:com.jsxs.conditional
 * @ClassName: MyImportBeanDefinitionRegistrar
 * @Description: TODO
 * @Version 1.0
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     *
     * @param importingClassMetadata : 当前类的注解信息
     * @param registry : BeanDefinition注册类
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 1.先判断我们的容器中是否有有我们将要注入IOC容器的组件
        if (registry.containsBeanDefinition("com.jsxs.bean.Color")) {
            // 第一个参数是我们注册后的组件名叫什么,第二个参数是我们需要使用类的全限定名 ⭐
            registry.registerBeanDefinition("RainBow",new RootBeanDefinition(RainBow.class));
        }
    }
}

2. 配置类编写

package com.jsxs.config;

import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.MyImportBeanDefinitionRegistrar;
import com.jsxs.conditional.MyImportSelector;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
// 快速的导入组件,id默认的是全限定名  ⭐⭐
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})

public class MyConfig2 {

    /**
     * 1. singleton 但是列的
     * 2.prototype 多实列   (默认值)
     * 3. 同一次请求创建一个实列
     * 4. 同一个session创建一个实列
     */
    @Scope(value = "singleton")
    @Bean("person2")
    @Lazy
    public Person person() {
        return new Person("张三2", 22);
    }

    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})
    @Bean("person01")
    public Person person01() {
        return new Person("张三01", 33);
    }

    @Conditional(LinuxConditional.class)
    @Bean("person02")
    public Person person02() {
        return new Person("张三02", 33);
    }

}

3.进行测试的操作

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getSystemEnvironment());
        // 3.获取我们具体的属性名
        System.out.println(environment.getProperty("os.name"));
        // 2.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

(4).FactoryBean

第四种在IOC容器中注入我们的组件的方法就是 我们Spring提供的 FactoryBean 工厂。我们只需要实现接口 FactoryBean< T> 这里的 T 就是我们需要的被注入IOC容器的组件类名称。

1. 实际要被注入IOC容器的类

package com.jsxs.bean;

/**
 * @Author Jsxs
 * @Date 2023/8/14 9:53
 * @PackageName:com.jsxs.bean
 * @ClassName: Color_factory
 * @Description: TODO
 * @Version 1.0
 */
public class Color_factory {
}

2.实现我们的接口

package com.jsxs.bean;

import org.springframework.beans.factory.FactoryBean;

/**
 * @Author Jsxs
 * @Date 2023/8/14 9:15
 * @PackageName:com.jsxs.bean
 * @ClassName: ColorFactoryBean
 * @Description: TODO
 * @Version 1.0
 */

// 创建一个Spring定义的FactoryBean  ⭐
public class ColorFactoryBean implements FactoryBean<Color_factory> {  // 这里我们指定我们的类型T为 我们想要注册的组件

    // 1.返回一个 ColorFactoryBean 对象,这个对象会添加到容器中去 ⭐
    @Override
    public Color_factory getObject() throws Exception {
        return new Color_factory();
    }

    // 2.返回类的类型  ⭐
    @Override
    public Class<?> getObjectType() {
        return Color_factory.class;
    }
    // 3. 是否是单列? ⭐

    /**
     *
     * @return : 假如说为true,那么我们就是单实列的,假如说为false,那么我们就不是单实列的。
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}

3.配置类中注册我们的ColorFactoryBean

    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

4.测试输出

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getSystemEnvironment());
        // 3.获取我们具体的属性名
        System.out.println(environment.getProperty("os.name"));
        // 2.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(applicationContext.getBean("colorFactoryBean")+"-----");
    }
}

遍历所有组件,我们只会得到表象为 colorFactory 这个组件。实际上我们通过组件的名字获取这个colorFactory便会得到我们实际上注入组件的类型和名字。

com.jsxs.bean.Color_factory@276438c9 这个是实际上注入的组件
在这里插入图片描述

(二)、组件的生命周期

1.@Bean指定初始化和销毁方法

(1). 使用配置文件进行自定义我们的初始化方法和销毁方法 (第一种)

在这里插入图片描述

(2).通过@Bean注解进行初始化和销毁 (第二种)

  1. 当对象创建完成后,并赋值好之后,调用初始化方法。
  2. 容器关闭之后,调用销毁的方法
 * Bean的生命周期
 *                      bean 创建 -> 初始化 -> 销毁的过程
 *                      容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 *                      1. init-method="" destroy-method=""
 *                      2. 构造(对象创建)
 *                          单实列: 在容器启动的时候创建对象
 *                          多实列: 在调用到组件的时候创建对象

1.Car.java

package com.jsxs.bean;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:12
 * @PackageName:com.jsxs.bean
 * @ClassName: Car
 * @Description: TODO
 * @Version 1.0
 */
public class Car {
    public Car(){
        System.out.println("Car Constructor ....");
    }

    public void init(){
        System.out.println("Car Init...");
    }

    public void destroy(){
        System.out.println("Car Destroy...");
    }
}

2.配置类

package com.jsxs.config;

import com.jsxs.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 *                      bean 创建 -> 初始化 -> 销毁的过程
 *                      容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 *                      1. init-method="" destroy-method=""
 *                      2. 构造(对象创建)
 *                          单实列: 在容器启动的时候创建对象
 *                          多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */

@Configuration
public class MainConfigOfLifeCycle {

    // 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。 ⭐
    @Bean(value = "car",destroyMethod = "destroy",initMethod = "init")
    public Car car(){
        return new Car();
    }
}

3.测试

package com.jsxs.Test;

import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

2.InitializingBean与 DisposableBean 进行初始化和销毁 (第三种)

(1).通过实现接口进行初始化和销毁的操作

1.我们需要自定义的bean只需要实现两个接口InitializingBean, DisposableBean即可

package com.jsxs.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * @Author Jsxs
 * @Date 2023/8/14 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Car01
 * @Description: TODO
 * @Version 1.0
 */
public class Car01 implements InitializingBean, DisposableBean {
    public Car01() {
    }

    // 1.初始化的操作
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Car01进行初始化...");
    }

    // 2.销毁的操作
    @Override
    public void destroy() throws Exception {
        System.out.println("Car01进行销毁...");
    }
}

package com.jsxs.config;

import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 * bean 创建 -> 初始化 -> 销毁的过程
 * 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 * 1. init-method="" destroy-method=""
 * 2. 构造(对象创建)
 * 单实列: 在容器启动的时候创建对象
 * 多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */

@Configuration
public class MainConfigOfLifeCycle {

    @Bean
    public Car01 car01() {
        return new Car01();
    }
}

在这里插入图片描述

3.使用JSR250规范 (第四种)

(1).@PostConstruct 和 @PreDestroy

@PostConstruct:在bean创建完成并且属性值赋值完成后执行初始化;
@PreDestroy:在容器销毁bean之前,通知容器进行清理工作;

1.需要被注册的组件

package com.jsxs.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * @Author Jsxs
 * @Date 2023/8/16 15:37
 * @PackageName:com.jsxs.bean
 * @ClassName: Dog
 * @Description: TODO
 * @Version 1.0
 */
public class Dog {
    public Dog() {
        System.out.println("dog constructor...");
    }

    @PostConstructpublic void init() {
        System.out.println("dog 初始化中...");
    }

    @PreDestroy()public void destroy() {
        System.out.println("dog 销毁中...");
    }
}

2.配置类: 注册需要的组件

package com.jsxs.config;

import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import com.jsxs.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 * bean 创建 -> 初始化 -> 销毁的过程
 * 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 * 1. init-method="" destroy-method=""
 * 2. 构造(对象创建)
 * 单实列: 在容器启动的时候创建对象
 * 多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */

@Configuration
public class MainConfigOfLifeCycle {

    // 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。
    @Bean(value = "car", destroyMethod = "destroy", initMethod = "init")
    public Car car() {
        return new Car();
    }

    @Bean
    public Car01 car01() {
        return new Car01();
    }


    @Beanpublic Dog dog(){
        return new Dog();
    }
}

3.测试

package com.jsxs.Test;

import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

4.BeanPostProcessor后置处理器 (第五种)

(1).BeanPostProcessor 后置处理器

后置处理器相当于在组件初始化之前做什么,初始化之后我们还做什么?

我们的Bean需要继承一个接口 BeanPostProcessor 并且完成两个方法。

在bean的初始化方法之前初始化方法之后进行一些处理工作。注意是初始化方法,和销毁方法没有一毛钱的关系。
初始化方法之前: 调用:postProcessBeforeInitialization()
初始化方法之后:调用:postProcessAfterInitialization()

即使没有自定义初始化方法,在组件创建前后,后置处理器方法也会执行。

1.注册我们的后置处理器

package com.jsxs.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @Author Jsxs
 * @Date 2023/8/16 15:51
 * @PackageName:com.jsxs.bean
 * @ClassName: MyBeanPostProcessor
 * @Description: TODO  我们需要实现一个 BeanPostProcessor 接口,并且完成两个方法
 * @Version 1.0
 */

@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor {  ⭐⭐
    /**
     * @param bean     新建组件的实列
     * @param beanName 新建组件实列的名字
     * @return 返回的是组件的信息
     * @throws BeansException
     */
    @Override  ⭐⭐⭐
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "----->" + bean);
        return bean;
    }

    /**
     * @param bean     新建组件的实列
     * @param beanName 新建组件实列的名字
     * @return  返回的是组件的信息
     * @throws BeansException
     */
    @Override ⭐⭐⭐⭐
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "----->" + bean);
        return bean;
    }
}

2.配置类扫描我们的后置处理器

package com.jsxs.config;

import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import com.jsxs.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 * bean 创建 -> 初始化 -> 销毁的过程
 * 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 * 1. init-method="" destroy-method=""
 * 2. 构造(对象创建)
 * 单实列: 在容器启动的时候创建对象
 * 多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")public class MainConfigOfLifeCycle {

    // 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。
    @Bean(value = "car", destroyMethod = "destroy", initMethod = "init")
    public Car car() {
        return new Car();
    }

    @Bean
    public Car01 car01() {
        return new Car01();
    }


    @Bean
    public Dog dog(){
        return new Dog();
    }
}

3.测试类

package com.jsxs.Test;

import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

5.Spring底层对BeanPostProcessor的使用

(1). 【案例1】在实体类中获取ioc容器

1.实体类

package com.jsxs.bean;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * @Author Jsxs
 * @Date 2023/8/16 15:37
 * @PackageName:com.jsxs.bean
 * @ClassName: Dog
 * @Description: TODO
 * @Version 1.0
 */
public class Dog implements ApplicationContextAware {  // ⭐继承这个IOC接口

    private ApplicationContext applicationContext;  // ⭐⭐
    
    public Dog() {
        System.out.println("dog constructor...");
    }

    @PostConstruct
    public void init() {
        System.out.println("dog 初始化中...");
    }

    @PreDestroy()
    public void destroy() {
        System.out.println("dog 销毁中...");
    }

    @Override // ⭐⭐⭐
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
    // ⭐⭐⭐⭐ 自己写一个获取IOC容器的方法 (便于调用)
    public ApplicationContext getApplicationContext(){
        return applicationContext;
    }
}

在这里插入图片描述
2.测试

package com.jsxs.Test;

import com.jsxs.bean.Dog;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        ConfigurableEnvironment environment1 = applicationContext.getEnvironment();
        System.out.println(environment1.getProperty("os.name"));

		// ⭐我们创建实列,并且  
        Dog dog = new Dog();
        ApplicationContext applicationContext1 = dog.getApplicationContext();
        for (String beanDefinitionName : applicationContext1.getBeanDefinitionNames()) {
            System.out.println("--->"+beanDefinitionName);
        }

    }
}

在这里插入图片描述

(三)、属性赋值相关的注解

    /**
     * 使用@Value赋值
     *    1、基本数值
     *    2、可以些SpEL,#{}
     *    3、可以写${},取出配置文件中的值(即在运行环境变量中的值).
     *      通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
     *      Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
     */

1.@Value

(1).普通属性赋值 和 SPEL表达式赋值

1.需要注册的组件

package com.jsxs.bean;

import org.springframework.beans.factory.annotation.Value;

/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {

	// ⭐ 
    @Value("李明")
    private String name;
    //  ⭐⭐ spel表达式
    @Value("#{20-2}")
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2.配置类

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/17 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfPropertyValues
 * @Description: TODO
 * @Version 1.0
 */

@Configuration
public class MainConfigOfPropertyValues {

    @Bean
    public Person person() {
        return new Person();
    }

}

3.测试

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MainConfigOfPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 9:07
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_PropertyValue
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_PropertyValue {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 2.通过组件名获取具体的组件信息
        Person person = (Person)annotationConfigApplicationContext.getBean("person");
        System.out.println(person);
    }
}

在这里插入图片描述

2. @PropertySource 加载外部配置文件

(1).使用配置文件的方式加载外部文件

1.beans.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--     1.包自动扫描: 凡是带有 @Controller @Service @Repository @Component     -->
    <context:component-scan base-package="com.jsxs"/>
    <!--    2.从外部环境中获取值 ⭐-->
    <context:property-placeholder location="classpath:person.properties"/>
    <!--   3. 通过Bean的方式进行我们的组件注入的操作  并设置作用域为多实例 -->
    
    <bean id="person" class="com.jsxs.bean.Person" scope="prototype">
    <!--    4.从外部环境中获取值使用EL表达式 ⭐⭐-->
        <property name="name" value="${person.name}"/>
        <property name="age" value="19"/>
    </bean>
</beans>

2.resource/beans.xml

person.name=李明

3.Person.java 实体类

package com.jsxs.bean;

import org.springframework.beans.factory.annotation.Value;

/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {
    /**
     *  1.基本数值
     *  2. 可以写Spel表达式,#{}
     *  3.可以写${},取出配置文件中的值(即在运行环境中的值)
     *  通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
     *  Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
     */

	//  ⭐⭐ 假如说这里加了@Value("${})注解也不会生效
    private String name;
    @Value("#{20-2}")
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

4.测试的操作

package com.jsxs.Test;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 10:15
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_PropertyValue_anno
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_PropertyValue_XML {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(applicationContext.getBean("person"));
    }
}

结果:我们取到了我们外部的文件,但是因为是中文,所以出现中文乱码的操作
在这里插入图片描述
在这里插入图片描述

(2).使用注解的方式 加载外部文件

1.Person.java

package com.jsxs.bean;

import org.springframework.beans.factory.annotation.Value;

/**
 * @Author Jsxs
 * @Date 2023/8/11 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Person
 * @Description: TODO
 * @Version 1.0
 */
public class Person {
    /**
     *  1.基本数值
     *  2. 可以写Spel表达式,#{}
     *  3.可以写${},取出配置文件中的值(即在运行环境中的值)
     *  通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
     *  Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
     */
	// ⭐⭐
    @Value("${person.name}")
    private String name;
    @Value("#{20-2}")
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2.配置文件 person.properties

person.name=asd

3.配置类

package com.jsxs.config;

import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * @Author Jsxs
 * @Date 2023/8/17 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfPropertyValues
 * @Description: TODO
 * @Version 1.0
 */
 // ⭐⭐ 配置文件不写了,但是我们需要在配置类上添加这个注解用来指定我们去哪个配置文件中进行获取数据
@PropertySource(value = {"classpath:person.properties"})
@Configuration
public class MainConfigOfPropertyValues {

    @Bean
    public Person person() {
        return new Person();
    }

}

4.测试类

package com.jsxs.Test;

import com.jsxs.bean.Person;
import com.jsxs.config.MainConfigOfPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 9:07
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_PropertyValue
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_PropertyValue {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
        for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 2.通过组件名获取具体的组件信息
        Person person = (Person)annotationConfigApplicationContext.getBean("person");
        System.out.println(person);
    }
}

在这里插入图片描述

(四)、自动装配

什么是自动装配?

Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值

1.@Autowired 自动装配

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
 *  (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
 * @Version 1.0
 */

(1). 自动装配(原理是从IOC容器中获得值并赋值)

1.BookMapper.java

package com.jsxs.mapper;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
@Repository
public class BookMapper {

    private String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookMapper{" +
                "label='" + label + '\'' +
                '}';
    }
}

2.BookService.java

package com.jsxs.service;

import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

//  ⭐⭐
    @Autowired
    private BookMapper bookMapper;

    public void print(){
        System.out.println("1111111111111111111"+bookMapper);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookMapper=" + bookMapper +
                '}';
    }
}

3.配置类的书写

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 applicationContext.getBean("bookMapper")
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")  // ⭐⭐
public class MainConfigOfAutowried {


}

4.测试

package com.jsxs.Test;

import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 判断我们是否是从IOC容器中获得值并赋值?
        BookMapper bean = applicationContext.getBean(BookMapper.class);
        BookService bean1 = applicationContext.getBean(BookService.class);
        System.out.println(bean1);
        System.out.println(bean);
    }
}

在这里插入图片描述

(2).@AutoWried(先类型后属性名)

这里我们第一个组件通过 @Reposity 注解扫描注入IOC容器,然后第二个组件通过 @Bean 的方式注入IOC容器。所以在这里我们就会发现在同一个IOC容器中有两个相同类型但不同名的组件。

1.BookMapper.java

package com.jsxs.mapper;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
 
 // 组件1
@Repository
public class BookMapper {

    private String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookMapper{" +
                "label='" + label + '\'' +
                '}';
    }
}

2.BookService.java

package com.jsxs.service;

import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

    @Autowired
    private BookMapper bookMapper;

    public void print(){
        System.out.println(bookMapper);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookMapper=" + bookMapper +
                '}';
    }
}

3.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 applicationContext.getBean("bookMapper")
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {
	
	// ⭐ 通过@Bena注入的同类型不同命组件
    @Bean("book2")
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

4.测试类

package com.jsxs.Test;

import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        BookService bean1 = applicationContext.getBean(BookService.class);
        System.out.println(bean1);

    }
}

证明在同一个IOC容器中有两个相同类型但不同名的组件。
在这里插入图片描述
在这里插入图片描述

(3).@Qualifier 配合 @AutoWried

假如我们注入一个组件并未指定他的组件名,那么组件名就会默认是 首字母小写的驼峰命名。所以使用这个组件的目的主要是为了解决 相同类型但不同组件名 的需求。

1.BookMapper.java

package com.jsxs.mapper;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
@Repository  // ⭐组件一
public class BookMapper {

    private String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookMapper{" +
                "label='" + label + '\'' +
                '}';
    }
}

2.BookService.java

package com.jsxs.service;

import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

    @Autowired  // ⭐ 自动装配
    @Qualifier("book2") // 指定名字
    private BookMapper bookMapper;

    public void print(){
        System.out.println(bookMapper);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookMapper=" + bookMapper +
                '}';
    }
}

3.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
 *  (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")  // ⭐扫描
public class MainConfigOfAutowried {

    @Bean("book2")  // ⭐⭐ 组件二
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

4.测试

package com.jsxs.Test;

import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        
        BookService bean1 = applicationContext.getBean(BookService.class);
        System.out.println(bean1);
    }
}

在这里插入图片描述

(4).@Primary 首选装配

常用于: 相同类型不同名的组件,然后相比于 @Quailfier() 的使用是 在使用组件的时候添加,@Primary是在组件创建的时候,就默认未首选装配。
1.BookMapper.java

package com.jsxs.mapper;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
@Repository
public class BookMapper {

    private String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookMapper{" +
                "label='" + label + '\'' +
                '}';
    }
}

2.BookService

package com.jsxs.service;

import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

    @Autowired
//    @Qualifier("book2")  ⭐⭐ 这里我们不指定使用哪个具体名字的组件进行装配
    private BookMapper bookMapper;

    public void print(){
        System.out.println("1111111111111111111"+bookMapper);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookMapper=" + bookMapper +
                '}';
    }
}

3.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
 *  (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
 *  (4).@Qualifier("book2")需要在使用的时候加入注解,比较繁琐,我们希望在注册组件的时候就作为首选组件 @Primary
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {

    @Primary   // ⭐⭐⭐ 组件在注册的时候,我们就指定使用这个组件进行装配 同类型不同组件命的组件
    @Bean("book2")
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

4.测试

package com.jsxs.Test;

import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        BookService bean1 = applicationContext.getBean(BookService.class);
        System.out.println(bean1);
    }
}

在这里插入图片描述

2.@Resource 和 @Inject [JSR标准]

Spring 还支持@Resource(JSR250) 和 @Inject(JSR330) [Java 规范]

(1).@Resource 自动装配

1.BookMapper.java

package com.jsxs.mapper;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
@Repository
public class BookMapper {

    private String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookMapper{" +
                "label='" + label + '\'' +
                '}';
    }
}

2.BookServer.java

package com.jsxs.service;

import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

    // ⭐⭐假如需要指定具体的组件的话,我们需要添加name属性,如果不添加name属性的话,就默认按照变量名查找 applicationContext.getBean("bookMapper")
    @Resource(name = "book2")
    private BookMapper bookMapper;

    public void print(){
        System.out.println("1111111111111111111"+bookMapper);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookMapper=" + bookMapper +
                '}';
    }
}

3.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
 *  (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
 *  (4).@Qualifier("book2")需要在使用的时候加入注解,比较繁琐,我们希望在注册组件的时候就作为首选组件 @Primary
 *
 *  2. @Resource: 自动注入 ⭐⭐
 *  (1).@Resource和@Autowried都可以对IOC容器的组件进行自动装配,但是@Autowried是按照组件的类型和名称进行自动装配的
 *  (2).@Resource不能支持@Primary和@Quailifer这两个注解
 *  3. @Inject: 自动注入
 *  (1).能够支持@Primary和@Quailifer , 和 @Autowired一样
 *  (2).但是需要导入一个包
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {

    @Primary  // ⭐⭐ 这个添加是没有用的,因为@Resource不支持
    @Bean("book2")
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

4.测试类

package com.jsxs.Test;

import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        BookService bean1 = applicationContext.getBean(BookService.class);
        System.out.println(bean1);
    }
}

在这里插入图片描述

(2).@Inject 自动装配

1.导入对应的 inject依赖

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

2.BookMapper.java

package com.jsxs.mapper;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:39
 * @PackageName:com.jsxs.Mapper
 * @ClassName: BookMapper
 * @Description: TODO
 * @Version 1.0
 */
@Repository
public class BookMapper {

    private String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookMapper{" +
                "label='" + label + '\'' +
                '}';
    }
}

3.BookService.java

package com.jsxs.service;

import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.inject.Inject;

/**
 * @Author Jsxs
 * @Date 2023/8/12 9:33
 * @PackageName:com.jsxs.service
 * @ClassName: BookService
 * @Description: TODO
 * @Version 1.0
 */

@Service
public class BookService {

    // @Inject 和 @Autowried 一模一样。 可以使用@Quailifer 和 @Primary ⭐⭐
    @Inject
    private BookMapper bookMapper;

    public void print(){
        System.out.println("1111111111111111111"+bookMapper);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookMapper=" + bookMapper +
                '}';
    }
}

4.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 * 自动装配:
 * Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 1. @Autowired:自动注入
 * 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
 *  (1).那么默认按照类型去容器中找对应的组件: 好比如:  applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
 *  (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
 *  (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
 *  (4).@Qualifier("book2")需要在使用的时候加入注解,比较繁琐,我们希望在注册组件的时候就作为首选组件 @Primary
 *
 *  2. @Resource: 自动注入
 *  (1).@Resource和@Autowried都可以对IOC容器的组件进行自动装配,但是@Autowried是按照组件的类型和名称进行自动装配的
 *  (2).@Resource不能支持@Primary和@Quailifer这两个注解
 *  3. @Inject: 自动注入 ⭐⭐
 *  (1).能够支持@Primary和@Quailifer , 和 @Autowired一样
 *  (2).但是需要导入一个包
 * @Version 1.0
 */

@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {

    @Primary  // ⭐⭐⭐ 可以使用
    @Bean("book2")
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

5.测试

package com.jsxs.Test;

import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        BookService bean1 = applicationContext.getBean(BookService.class);
        System.out.println(bean1);
    }
}

在这里插入图片描述

3.@Autowried自动装配原理

在这里插入图片描述

通过点击 @Autowried的源码,我们发现这个注解可以标注在构造器上方法上等。

(1).标注在Set方法位置上

    // 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值的操作。
    // 方法使用的参数,自定义类型的参数的值是从IOC容器中获取, 比如说 我们启动IOC容器后,就会在IOC容器中找类型未 Car.class 类型的组件

如果需要自动装配的话,项目要求非要方法上的话,那么一定要优先选择 set 方法
1. Car.java

package com.jsxs.bean;

import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:12
 * @PackageName:com.jsxs.bean
 * @ClassName: Car
 * @Description: TODO
 * @Version 1.0
 */

@Repositorypublic class Car {

    public Car(){
        System.out.println("Car Constructor ....");
    }

    public void init(){
        System.out.println("Car Init...");
    }

    public void destroy(){
        System.out.println("Car Destroy...");
    }
}

2.Boss.java

package com.jsxs.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/17 17:34
 * @PackageName:com.jsxs.bean
 * @ClassName: Boss
 * @Description: TODO
 * @Version 1.0
 */

@Repository  ⭐⭐
public class Boss {
    private Car car;

    public Boss(Car car) {
        this.car = car;
    }

    public Boss() {
    }

    public Car getCar() {
        return car;
    }

    @Autowired  ⭐⭐⭐
    // 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值的操作。
    // 方法使用的参数,自定义类型的参数的值是从IOC容器中获取, 比如说 我们启动IOC容器后,就会在IOC容器中找类型未 Car.class 类型的组件
    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Boss{" +
                "car=" + car +
                '}';
    }
}

3.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 **/

@Configuration
@ComponentScan(value = "com.jsxs")  //⭐⭐⭐ 扫描
public class MainConfigOfAutowried {

    @Primary
    @Bean("book2")
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

4.测试

package com.jsxs.Test;

import com.jsxs.bean.Boss;
import com.jsxs.bean.Car;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);

        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

		// 判断是否是是在IOC容器中获取的
        Boss bean = applicationContext.getBean(Boss.class);
        Car bean1 = applicationContext.getBean(Car.class);
        System.out.println(bean);
        System.out.println(bean1);
    }
}

在这里插入图片描述

(2).标注在有参构造方法上

创建对象默认是调用无参构造方法的,但是因为我们在有参构造方法上添加了@Autowried,那么我们就会在IOC创建后,创建对象的话就会使用有参构造函数进行创建了。
1.Car.java

package com.jsxs.bean;

import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/14 17:12
 * @PackageName:com.jsxs.bean
 * @ClassName: Car
 * @Description: TODO
 * @Version 1.0
 */

@Repository
public class Car {

    public Car(){
        System.out.println("Car Constructor ....");
    }

    public void init(){
        System.out.println("Car Init...");
    }

    public void destroy(){
        System.out.println("Car Destroy...");
    }
}

2.Boss.java

package com.jsxs.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

/**
 * @Author Jsxs
 * @Date 2023/8/17 17:34
 * @PackageName:com.jsxs.bean
 * @ClassName: Boss
 * @Description: TODO
 * @Version 1.0
 */

@Repository  //⭐扫描后默认加载IOC容器中的组件,容器启动就会(单实列饿汉)调用无参构造器创建对象,再进行初始化赋值等操作。⭐
public class Boss {
    private Car car;

    @Autowired ⭐⭐
    // 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值的操作。
    // 方法使用的参数,自定义类型的参数的值是从IOC容器中获取, 比如说 我们启动IOC容器后,就会在IOC容器中找类型未 Car.class 类型的组件
    public Boss(Car car) {
        this.car = car;
    }

    public Boss() {
    }

    public Car getCar() {
        return car;
    }


    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Boss{" +
                "car=" + car +
                '}';
    }
}

3.配置类

package com.jsxs.config;

import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:14
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfAutowried
 * @Description: TODO
 **/

@Configuration
@ComponentScan(value = "com.jsxs") //⭐⭐扫描
public class MainConfigOfAutowried {

    @Primary
    @Bean("book2")
    public BookMapper bookMapper() {
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

}

4.测试

package com.jsxs.Test;

import com.jsxs.bean.Boss;
import com.jsxs.bean.Car;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 11:23
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Autowried
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Autowried {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);

        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
		
		
        Boss bean = applicationContext.getBean(Boss.class);
        Car bean1 = applicationContext.getBean(Car.class);
        System.out.println(bean);
        System.out.println(bean1);
    }
}

在这里插入图片描述

(3).@Bean + 方法参数

@Bean+方法参数 ,这里的参数默认是从IOC容器中获取的。默认不写@Autowried 也会自动装配

    @Primary
    @Bean("book2")
    public BookMapper bookMapper(Car car) {  //⭐ 这个Car 也是从IOC容器中获取的
        BookMapper bookMapper = new BookMapper();
        bookMapper.setLabel("2");
        return bookMapper;
    }

4.自定义组件使用Spring容器底层的一些组件

(1).xxxAware

自定义组件实现xxxAware: 在创建对象的时候,会调用接口规定的方法注入相关组件。Aware

在这里插入图片描述

在这里插入图片描述

5.@Profile 切换多个应用场景

(1). 环境搭建

1.依赖

        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

2.配置类

package com.jsxs.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * @Author Jsxs
 * @Date 2023/8/17 20:59
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfProfile
 * @Description: TODO   Profile:
 *                          Spring为我们提供的可以根据当前环境,动态的激活和切换一系列bean的功能
 *                          (1).开发环境、测试环境、生产环境
 *
 * @Version 1.0
 */
@PropertySource("classpath:/db.properties")  // 1. 因为要读取外部的文件,所以我们需要指定外部的文件的位置
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware {  // 2.实现EmbeddedValueResolverAware解析器接口,这个接口主要是能够解析 ${} 和 #{}

    @Value("${db.user}")  // 3.  获取外部的文件,并赋值
    private String user;
    @Value("${db.password}")
    private String password;
    @Value("${db.driverClass}")
    private String Driver;
        // 4. 进行依赖注入的操作
    private StringValueResolver stringValueResolver;

    @Bean("DataSourceTest")
    public DataSource dataSourceTest() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/demo1");
        dataSource.setDriverClass(Driver);
        return dataSource;
    }

    @Bean("DataSourceDev")
    public DataSource dataSourceDev() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/library");
        dataSource.setDriverClass(Driver);
        return dataSource;
    }

    @Bean("DataSourceProd")
    public DataSource dataSourceProd() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ckqn");
        // 5. 获取解析到的值
        String value = stringValueResolver.resolveStringValue("${db.driverClass}");
        dataSource.setDriverClass(value);
        return dataSource;
    }

    // 6. 依赖注入
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.stringValueResolver=resolver;
    }
}

3.外部资源文件

db.user=root
db.password=121788
db.driverClass=com.mysql.jdbc.Driver

4.测试

package com.jsxs.Test;

import com.jsxs.config.MainConfigOfProfile;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 21:31
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Profile
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Profile {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

(2).根据环境注册bean (环境切换)

如何切换环境呢?

/**
     * 切换环境的方式:
     *  1、使用命令行动态参数:在虚拟机参数位置加载-Dspring.profiles.active=test(test是测试的环境标识)
     *  2、代码的方式激活某种环境
     */
package com.jsxs.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * @Author Jsxs
 * @Date 2023/8/17 20:59
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfProfile
 * @Description: TODO   @Profile:指定组件在哪个环境的情况下才能被注册到容器中。 @Bean: 任何环境下都可以被注册到容器中
 *                      Spring为我们提供的可以根据当前环境,动态的激活和切换一系列bean的功能
 *                      (1).开发环境、测试环境、生产环境
 *                      (2).加了环境标识的bean,只有这个环境被激活的时候才能注册
 * @Version 1.0
 */
@PropertySource("classpath:/db.properties")  // 1. 因为要读取外部的文件,所以我们需要指定外部的文件的位置 ⭐
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware {  // 2.实现EmbeddedValueResolverAware解析器接口,这个接口主要是能够解析 ${} 和 #{}

    @Value("${db.user}")  // 3.  获取外部的文件,并赋值
    private String user;
    @Value("${db.password}")
    private String password;
    @Value("${db.driverClass}")
    private String Driver;
    // 4. 进行依赖注入的操作
    private StringValueResolver stringValueResolver;

//    @Profile("default")  假如我们写的是default,那么就会使用注解下方的数据源
    @Profile("test") ⭐⭐
    @Bean("DataSourceTest")
    public DataSource dataSourceTest() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/demo1");
        dataSource.setDriverClass(Driver);
        return dataSource;
    }

    @Profile("dev")⭐⭐⭐
    @Bean("DataSourceDev")
    public DataSource dataSourceDev() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/library");
        dataSource.setDriverClass(Driver);
        return dataSource;
    }

    @Profile("prod")⭐⭐⭐
    @Bean("DataSourceProd")
    public DataSource dataSourceProd() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ckqn");
        // 5. 获取解析到的值
        String value = stringValueResolver.resolveStringValue("${db.driverClass}");
        dataSource.setDriverClass(value);
        return dataSource;
    }

    // 6. 依赖注入
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.stringValueResolver = resolver;
    }
}

package com.jsxs.Test;

import com.jsxs.config.MainConfigOfProfile;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author Jsxs
 * @Date 2023/8/17 21:31
 * @PackageName:com.jsxs.Test
 * @ClassName: IOCTest_Profile
 * @Description: TODO
 * @Version 1.0
 */
public class IOCTest_Profile {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 1.指定环境 ⭐
        applicationContext.getEnvironment().setActiveProfiles("test");
        // 2.指定配置类 ⭐⭐
        applicationContext.register(MainConfigOfProfile.class);
        // 3.刷新容器  ⭐⭐⭐
        applicationContext.refresh();
        // 4.输出所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/77955.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JDBC API

DriverManager : 注册驱动 Class.forName("com.mysql.jdbc.Driver"); 获取数据库连接 url &#xff1a; 连接路径 语法&#xff1a;jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2… 示例&#xff1a;jdbc:mysql://127.0.0.1:3306/db1 细…

IOS开发-XCode14介绍与入门

IOS开发-XCode14介绍与入门 1. XCODE14的小吐槽2. XCODE的功能bar一览3. XCODE项目配置一览4. XCODE更改DEBUG/RELEASE模式5. XCODE单元测试 1. XCODE14的小吐槽 iOS开发工具一直有个毛病&#xff0c;就是新版本的开发工具的总会有一些奇奇怪怪的bug。比如在我的Mac-Pro&#…

当众讲话培训的需求分析

标题&#xff1a;当众讲话培训的需求分析 摘要&#xff1a;当众讲话是现代社会中一项重要的技能&#xff0c;对于个人和职业发展都具有重要意义。然而&#xff0c;许多人面临着当众讲话的困难和挑战。本论文旨在分析当众讲话培训的需求&#xff0c;探讨为什么人们需要这种培训…

Java版工程项目管理系统平台+企业工程系统源码+助力工程企业实现数字化管理 em

​ 鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部…

vueuse常用方法

useDateFormat 时间格式化 <script setup lang"ts">import { useNow, useDateFormat } from vueuse/coreconst formatted useDateFormat(useNow(), YYYY-MM-DD HH:mm:ss)</script><template><div>{{ formatted }}</div> </templa…

【实际开发21】- 项目部署

目录 1. 项目打包方式就两种 : war、jar 1. Windows 环境运行 Jar 包 2. Windows 后台运行 jar 包 1. cmd 下执行方式 2. bat 批处理方式 - ( Batch ) 3. 启动 : 在 xx.jar 同级目录下建立 run.bat 文件 4. 项目部署打包 忽略 test 文件 2. CICD 自动化部署 3. 代码质…

讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?

同时向讯飞星火、文心一言和通义千问三个国产AI模型提个相同的问题&#xff1a; “python 写一个贪吃蛇的游戏代码” 看哪一家AI写的程序直接能用&#xff0c;谁就胜出&#xff01; 讯飞星火 讯飞星火给出的代码&#xff1a; import pygame import sys import random# 初…

分布式 - 消息队列Kafka:Kafka生产者发送消息的分区策略

文章目录 01. Kafka 分区的作用02. PartitionInfo 分区源码03. Partitioner 分区器接口源码04. 自定义分区器05. 默认分区器 DefaultPartitioner06. 随机分区分配 RoundRobinPartitioner07. 黏性随机分区分配 UniformStickyPartitioner08. 为什么Kafka 2.4 版本后引入黏性分区策…

ViewUI表格Table嵌套From表单-动态校验数据合法性的解决方法

项目场景&#xff1a; 项目需求&#xff1a;在表格中实现动态加减数据&#xff0c;并且每行表格内的输入框&#xff0c;都要动态校验数据&#xff0c;校验不通过&#xff0c;不让提交数据&#xff0c;并且由于表格内部空间较小&#xff0c;我仅保留红边框提示&#xff0c;文字…

【JVM】Java内存泄露的排查思路?

文章目录 Java内存为什么会泄露&#xff1f;java内存泄露的排查思路 Java内存为什么会泄露&#xff1f; Java内存泄露&#xff08;Memory Leak&#xff09;是指在Java程序中&#xff0c;无用的对象占用了堆内存&#xff0c;但无法被垃圾回收器回收释放&#xff0c;从而导致可用…

根据Dockerfile创建容器案例讲解

-f为dokerfile的路径&#xff0c; -t为新镜像的名称及版本。 后面这个点是寻址路径。

深入篇【C++】手搓模拟实现二叉搜索树(递归/非递归版本)常见应用场景(K模型与KV模型)

深入篇【C】手搓模拟实现二叉搜索树(递归/非递归版本&#xff09;&&常见应用场景 Ⅰ.二叉搜索树概念Ⅱ.二叉搜索树模拟实现(递归与非递归)①.定义结点②.构造二叉树③.插入结点④.删除结点(重要)⑤.查找结点⑥.析构二叉树⑦.拷贝二叉树⑧.二叉树赋值 Ⅲ.二叉搜索树应用…

Docker服务编排Docker Compose介绍

1.服务编排概念 2.Docker Compose介绍 3.Docker Compose安装及使用

蓝桥杯每日N题(杨辉三角形)

大家好 我是寸铁 希望这篇题解对你有用&#xff0c;麻烦动动手指点个赞或关注&#xff0c;感谢您的关注 不清楚蓝桥杯考什么的点点下方&#x1f447; 考点秘籍 想背纯享模版的伙伴们点点下方&#x1f447; 蓝桥杯省一你一定不能错过的模板大全(第一期) 蓝桥杯省一你一定不…

【Docker】 使用Docker-Compose 搭建基于 WordPress 的博客网站

引 本文将使用流行的博客搭建工具 WordPress 搭建一个私人博客站点。部署过程中使用到了 Docker 、MySQL 。站点搭建完成后经行了发布文章的体验。 WordPress WordPress 是一个广泛使用的开源内容管理系统&#xff08;CMS&#xff09;&#xff0c;用于构建和管理网站、博客和…

[Go版]算法通关村第十一关白银——位运算的高频算法题

目录 专题1&#xff1a;位移的妙用题目&#xff1a;位1的个数&#xff08;也被称为汉明重量&#xff09;解法1&#xff1a;遍历所有位&#xff0c;判断每个位的数字是否是1Go代码 解法2&#xff1a;依次消除每个1的位 numnum&(num-1)Go代码 题目&#xff1a;比特位计数思路…

C#引用Web Service 类型方法,添加搜索本地服务器Web Service 接口调用方法

首先保证现在网络能调用web service接口&#xff0c;右键项目添加服务引用 ![![在这里插入图片描述](https://img-blog.csdnimg.cn/555ba4fa5e2a418f8f85539a9406bcd6.png) 点击高级 添加web服务 输入搜索的服务器接口&#xff0c;选中你要添加调用的方法即可 添加完成调用方…

win10在vmware16.2.3上安装macos13.1系统

第一步、安装vmware版本信息如下 第二步、下载unlocker426放到安装文件夹 第三步、管理员身份运行unlock.exe 第四步、运行vmware新建虚拟机 第五步、启动新创建的虚拟机macOS13.1并选择语言 第六步、选择磁盘工具抹掉格式化安装磁盘 第七步、格式化完成后退出磁盘工具 第八步、…

DAY4,ARM(用c语言点亮LED灯,封装库代码,软件编程控制硬件)

---gpio.h头文件--- #ifndef __LED_H__ #define __LED_H__//1RCC_MP_AHB4ENSETR寄存器封装 #define RCC_MP_AHB4ENSETR (*(volatile unsigned int*)0x50000a28)//2GPIO封装结构体 typedef struct {volatile unsigned int MODER;volatile unsigned int OTYPER;volatile unsigne…

SpringBoot集成Solr(二)搜索数据

SpringBoot集成Solr&#xff08;二&#xff09;搜索数据 1.1 构建查询条件 //创建 solr查询参数对象 SolrQuery query new SolrQuery(); StringBuilder params new StringBuilder(); params.append(" subject_s:*").append(text).append("*"); params.a…