129.【Spring 注解_IOC】

news2024/11/17 1:40:11

Spring 注解_IOC容器

  • (一)、组件注册
    • 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依赖: xml文件和注解的包
<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.coloradmin.cn/o/908711.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【stable-diffusion使用扩展+插件和模型资源(上】

文章目录 前言一、插件推荐1.qrcode-monster2.sd-webui-openpose-editor3.sd-webui-depth-lib4.roop&#xff08;换脸插件&#xff09;5.sd-webui-qrcode-toolkit&#xff08;艺术二维码&#xff09;5.光源控制6.二次元转真人7.动态视频转场&#xff08;loopback-wave&#xff…

Unity中实现获取InputField选中的文字

一&#xff1a;前言 获取到选中的文字&#xff1a;哈哈 二&#xff1a;实现 UGUI的InputField提供了selectionAnchorPosition和selectionFocusPosition&#xff0c;开始选择时的光标下标和当前光标下标 using UnityEngine; using UnityEngine.EventSystems; using UnityEngin…

Java之包,权限修饰符,final关键字详解

包 2.1 包 包在操作系统中其实就是一个文件夹。包是用来分门别类的管理技术&#xff0c;不同的技术类放在不同的包下&#xff0c;方便管理和维护。 在IDEA项目中&#xff0c;建包的操作如下&#xff1a; 包名的命名规范&#xff1a; 路径名.路径名.xxx.xxx // 例如&#xff…

视频高效批量剪辑,轻松制作底片效果的视频,实现剪辑自由

大家好&#xff01;在进行视频剪辑时&#xff0c;有时候我们需要对多个视频进行制作底片效果&#xff0c;以便获得更好的视觉效果。为了让您能够轻松制作底片效果视频&#xff0c;我们特别推出了一款便捷工具&#xff0c;让您能够快速制作视频底片效果&#xff0c;实现更加出色…

搞定二叉树

树的名词与概念 子树&#xff1a;树是一个有限集合&#xff0c;子树则是该集合的子集。就像套娃一样&#xff0c;一棵树下面还包含着其子树。比如&#xff0c;树T1 的子树为 树T2、T3、T4&#xff0c;树T2的子树为 T5、T6 。 上图中还有许多子树没有标记出来 。 结点(Node)&am…

wustojc3013字母对应的ASCII 码

#include <stdio.h> int main() {char b;scanf("%c",&b);printf("%d",b);//利用默认强转&#xff0c;字符会打印成ascll码值return 0;}

【韩顺平 零基础30天学会Java】程序流程控制(2days)

day1 程序流程控制&#xff1a;顺序控制、分支控制、循环控制 顺序控制&#xff1a;从上到下逐行地执行&#xff0c;中间没有任何判断和跳转。 Java中定义变量时要采用合法的前向引用。 分支控制if-else&#xff1a;单分支、双分支和多分支。 单分支 import java.util.Scann…

【校招VIP】测试专业课之OSI七层模型

考点介绍&#xff1a; 在 OSI 模型中&#xff0c;每一层都依赖于下一层&#xff0c;并将数据传递给下一层。同时&#xff0c;每一层也可以向上一层提供特定的服务。这种分层结构使得网络管理员可以更轻松地管理网络&#xff0c;同时使得网络协议的设计更加灵活。 『测试专业课…

学习设计模式之观察者模式,但是宝可梦

前言 作者在准备秋招中&#xff0c;学习设计模式&#xff0c;做点小笔记&#xff0c;用宝可梦为场景举例&#xff0c;有错误欢迎指出。 观察者模式 观察者模式定义了一种一对多的依赖关系&#xff0c;一个对象的状态改变&#xff0c;其他所有依赖者都会接收相应的通知。 所…

阿里云通用算力型u1云服务器CPU性能详细说明

​阿里云服务器u1是通用算力型云服务器&#xff0c;CPU采用2.5 GHz主频的Intel(R) Xeon(R) Platinum处理器&#xff0c;通用算力型u1云服务器不适用于游戏和高频交易等需要极致性能的应用场景及对业务性能一致性有强诉求的应用场景(比如业务HA场景主备机需要性能一致)&#xff…

外贸邮箱前缀选择指南:技巧揭秘!

外贸邮箱前缀用什么好&#xff1f;常见的外贸邮箱前缀有 zoho.com.cn&#xff0c; foxmail.com&#xff0c; hotmail.com&#xff0c; outlook.com&#xff0c; yahoo.com等等。那么这些前缀之间又有什么区别呢&#xff1f;选择哪个前缀对外贸业务更有利呢&#xff1f; 首先&am…

如何通过Side Effects来使得你使用Compose变的得心应手?

作者&#xff1a;clwater 虽然我使用Compose已经有了一段时间的, 但我还是觉得使用起来束手束脚的. 究其原因, 大概是coding时的思路还没有完全转换过来, 还没有沉浸在"Compose is Function"之中. 和我们熟悉的View不同, 当我们调用Compose之后, 我们就失去了它的修改…

代码审计-审计工具介绍-DAST+SAST+IAST项目

DASTSASTIAST项目介绍 DAST&#xff1a; 动态应用程序安全测试&#xff08;Dynamic Application Security Testing&#xff09;技术在测试或运行阶段分析应用程序的动态运行状态。它模拟黑客行为对应用程序进行动态攻击&#xff0c;分析应用程序的反应&#xff0c;从而确定该We…

*看门狗2_思考多组看门狗对多任务的监控

多任务系统中 一般结合嵌入式操作系统&#xff0c;设置一个优先级级别最高的任务作为监视器&#xff0c;以监视各个应用任务是否正常运行&#xff0c;该监视器即为软件看门狗&#xff0c;该任务对其他任务都设定一个计时器&#xff0c;每个被监视的任务在设定的时间内对软件看门…

企业级私有化部署即时通讯,完美替代SaaS平台

在数字化转型的时代&#xff0c;企业越来越需要安全、高效和可扩展的解决方案来管理其运营。作为通用办公行业的领军品牌&#xff0c;WorkPlus在企业级私有化部署领域成为改变者。凭借其尖端功能和全面的功能性&#xff0c;WorkPlus提供了传统的软件即服务&#xff08;SaaS&…

SELinux 入门 pt.1

哈喽大家好&#xff0c;我是咸鱼 文章《SELinux 导致 Keepalived 检测脚本无法执行》以【keepalived 无法执行检测脚本】为案例向大家简单介绍了关于 SELinux 的一些概念 比如说什么是自主访问控制 DAC 和 强制访问控制 MAC&#xff1b;SELinux 安全上下文的概念等等 那么今…

洛谷 P2715 ccj与zrz之在回家的路上 艰辛的解题过程

时隔将近两个月&#xff0c;我回来了哈哈哈哈哈哈哈哈哈。 看着一周小结的排名越来越低太难受了&#xff0c;于是我回来继续写文章 今天这道题其实不难&#xff0c;重点是说一下解题过程中遇到的麻烦和坑点 题目描述 给出一个算式&#xff08;a*bc或a/bc或abc或a-bc&#xff0…

深入理解JMM和并发三大特性

并发和并行 并发和并行的目的都是为了使CPU的使用率最大化&#xff0c;这两个概念也是我们容易混淆的。 并行&#xff08;Parallel&#xff09; 并行是指在同一时刻&#xff0c;有多条指令在多个处理器上同时执行&#xff0c;因为并行要求程序能同时执行多个操作&#xff0c…

APP上线为什么要提前部署安全产品呢?

一般平台刚上线或者日活跃量比较高的时候&#xff0c;很容易成为攻击者的目标&#xff0c;服务器如果遭遇黑客攻击&#xff0c;资源耗尽会导致平台无法访问&#xff0c;业务也无法正常开展&#xff0c;服务器一旦触发黑洞机制&#xff0c;就会被拉进黑洞很长一段时间&#xff0…

MySQL下载安装配置

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…