129.【Spring 注解 IOC】

news2024/11/24 15:56:35

Spring 注解

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

在这里插入图片描述

(一)、组件注册

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

(1).无注解注入方式

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

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

    private String name;
    private Integer age;

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

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

  1. 在resource目录下的beans.xml配置文件中通过< bean>< /bean>标签注入类实例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

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

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

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

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

    }
}

在这里插入图片描述

(2).注解注入方式

1.MyConfig.java

package com.jsxs.config;

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

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

@Configuration
public class MyConfig {

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

2.Main.java

package com.jsxs;

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

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

在这里插入图片描述

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

(1).无注解扫描方式

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

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

import org.springframework.stereotype.Repository;

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

package com.jsxs.service;

import org.springframework.stereotype.Service;

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

@Service
public class BookService {

}

package com.jsxs.controller;

import org.springframework.stereotype.Controller;

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

1. beans.xml

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

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

</beans>

2.IOCTest.java

package com.jsxs.Test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

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

在这里插入图片描述

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

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

package com.jsxs.config;

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

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

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

在这里插入图片描述

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

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

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

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

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

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

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

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

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

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

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

@Configuration
public class MyConfig {

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

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

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

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

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

package com.jsxs.config;

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

import java.io.IOException;

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

2. 配置文件是这样写的

package com.jsxs.config;

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

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

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

})
@Configuration
public class MyConfig {

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

在这里插入图片描述

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

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

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

package com.jsxs.config;

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

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

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

2.测试类

package com.jsxs.Test;

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

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

在这里插入图片描述

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

package com.jsxs.config;

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

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

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

package com.jsxs.Test;

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

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

在这里插入图片描述

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

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

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

</beans>

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

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

5.@Layz-bean懒加载

(1).懒加载

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

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

package com.jsxs.config;

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

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

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

2.进行测试

package com.jsxs.Test;

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

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

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

6.@Conditional 按照条件注册bean

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

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

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

package com.jsxs.conditional;

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

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

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

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

LinuxConditional.java

package com.jsxs.conditional;

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

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

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

MyConfig2.java

package com.jsxs.config;

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

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


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

在这里插入图片描述

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

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

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

(1).@Import

1.要注册的组件

package com.jsxs.bean;

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

2.@Import注解放在类上

package com.jsxs.config;

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

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

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

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

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

}

3.测试

package com.jsxs.Test;

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

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

    }
}

在这里插入图片描述

(2).ImportSelector ⭐

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

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

package com.jsxs.conditional;

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

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

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

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

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

package com.jsxs.config;

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

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

public class MyConfig2 {

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

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

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

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

在这里插入图片描述

(3). ImportBeanDefinitionRegistrar

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

package com.jsxs.conditional;

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

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

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

2. 配置类编写

package com.jsxs.config;

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

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

public class MyConfig2 {

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

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

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

}

3.进行测试的操作

package com.jsxs.Test;

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

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

在这里插入图片描述

(4).FactoryBean

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

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

package com.jsxs.bean;

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

2.实现我们的接口

package com.jsxs.bean;

import org.springframework.beans.factory.FactoryBean;

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

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

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

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

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

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

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

4.测试输出

package com.jsxs.Test;

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

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

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

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

(二)、组件的生命周期

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

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

在这里插入图片描述

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

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

1.Car.java

package com.jsxs.bean;

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

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

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

2.配置类

package com.jsxs.config;

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

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

@Configuration
public class MainConfigOfLifeCycle {

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

3.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

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

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

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

package com.jsxs.bean;

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

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

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

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

package com.jsxs.config;

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

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

@Configuration
public class MainConfigOfLifeCycle {

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

在这里插入图片描述

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

(1).@PostConstruct 和 @PreDestroy

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

1.需要被注册的组件

package com.jsxs.bean;

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

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

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

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

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

package com.jsxs.config;

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

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

@Configuration
public class MainConfigOfLifeCycle {

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

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


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

3.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

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

(1).BeanPostProcessor 后置处理器

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

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

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

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

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

package com.jsxs.bean;

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

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

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

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

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

package com.jsxs.config;

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

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

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

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

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


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

3.测试类

package com.jsxs.Test;

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

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

在这里插入图片描述

5.Spring底层对BeanPostProcessor的使用

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

1.实体类

package com.jsxs.bean;

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

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

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

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

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

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

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

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

package com.jsxs.Test;

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

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

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

    }
}

在这里插入图片描述

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

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

1.@Value

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

1.需要注册的组件

package com.jsxs.bean;

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

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

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

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

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

2.配置类

package com.jsxs.config;

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

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

@Configuration
public class MainConfigOfPropertyValues {

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

}

3.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

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

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

1.beans.xml文件

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

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

2.resource/beans.xml

person.name=李明

3.Person.java 实体类

package com.jsxs.bean;

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

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

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

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

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

4.测试的操作

package com.jsxs.Test;

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

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

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

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

1.Person.java

package com.jsxs.bean;

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

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

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

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

2.配置文件 person.properties

person.name=asd

3.配置类

package com.jsxs.config;

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

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

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

}

4.测试类

package com.jsxs.Test;

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

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

在这里插入图片描述

(四)、自动装配

什么是自动装配?

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

1.@Autowired 自动装配

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

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

1.BookMapper.java

package com.jsxs.mapper;

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

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

    private String label="1";

    public String getLabel() {
        return label;
    }

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

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

2.BookService.java

package com.jsxs.service;

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

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

@Service
public class BookService {

//  ⭐⭐
    @Autowired
    private BookMapper bookMapper;

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

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

3.配置类的书写

package com.jsxs.config;

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

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

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


}

4.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

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

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

1.BookMapper.java

package com.jsxs.mapper;

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

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

    private String label="1";

    public String getLabel() {
        return label;
    }

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

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

2.BookService.java

package com.jsxs.service;

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

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

@Service
public class BookService {

    @Autowired
    private BookMapper bookMapper;

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

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

3.配置类

package com.jsxs.config;

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

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

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

}

4.测试类

package com.jsxs.Test;

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

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

    }
}

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

(3).@Qualifier 配合 @AutoWried

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

1.BookMapper.java

package com.jsxs.mapper;

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

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

    private String label="1";

    public String getLabel() {
        return label;
    }

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

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

2.BookService.java

package com.jsxs.service;

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

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

@Service
public class BookService {

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

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

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

3.配置类

package com.jsxs.config;

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

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

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

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

}

4.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

(4).@Primary 首选装配

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

package com.jsxs.mapper;

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

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

    private String label="1";

    public String getLabel() {
        return label;
    }

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

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

2.BookService

package com.jsxs.service;

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

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

@Service
public class BookService {

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

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

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

3.配置类

package com.jsxs.config;

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

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

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

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

}

4.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

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

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

(1).@Resource 自动装配

1.BookMapper.java

package com.jsxs.mapper;

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

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

    private String label="1";

    public String getLabel() {
        return label;
    }

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

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

2.BookServer.java

package com.jsxs.service;

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

import javax.annotation.Resource;

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

@Service
public class BookService {

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

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

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

3.配置类

package com.jsxs.config;

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

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

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

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

}

4.测试类

package com.jsxs.Test;

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

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

在这里插入图片描述

(2).@Inject 自动装配

1.导入对应的 inject依赖

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

2.BookMapper.java

package com.jsxs.mapper;

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

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

    private String label="1";

    public String getLabel() {
        return label;
    }

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

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

3.BookService.java

package com.jsxs.service;

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

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

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

@Service
public class BookService {

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

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

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

4.配置类

package com.jsxs.config;

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

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

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

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

}

5.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

3.@Autowried自动装配原理

在这里插入图片描述

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

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

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

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

package com.jsxs.bean;

import org.springframework.stereotype.Repository;

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

@Repositorypublic class Car {

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

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

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

2.Boss.java

package com.jsxs.bean;

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

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

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

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

    public Boss() {
    }

    public Car getCar() {
        return car;
    }

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

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

3.配置类

package com.jsxs.config;

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

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

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

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

}

4.测试

package com.jsxs.Test;

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

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

    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);

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

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

在这里插入图片描述

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

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

package com.jsxs.bean;

import org.springframework.stereotype.Repository;

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

@Repository
public class Car {

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

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

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

2.Boss.java

package com.jsxs.bean;

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

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

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

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

    public Boss() {
    }

    public Car getCar() {
        return car;
    }


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

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

3.配置类

package com.jsxs.config;

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

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

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

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

}

4.测试

package com.jsxs.Test;

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

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

    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);

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

在这里插入图片描述

(3).@Bean + 方法参数

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

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

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

(1).xxxAware

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

在这里插入图片描述

在这里插入图片描述

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

(1). 环境搭建

1.依赖

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

2.配置类

package com.jsxs.config;

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

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

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

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

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

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

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

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

3.外部资源文件

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

4.测试

package com.jsxs.Test;

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

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

在这里插入图片描述

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

如何切换环境呢?

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

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

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

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

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

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

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

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

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

package com.jsxs.Test;

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

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

在这里插入图片描述

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

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

相关文章

宝塔端口监听不到端口

场景&#xff1a; 两个服务器同时在安装nginx 出问题导致20011没有在监听&#xff0c;重新删除nginx 就行了 当时一直以为是安全组没有放过端口&#xff0c;其实是没有监听 排查问题 php -S 0.0.0.0:端口 如果可以访问说明链接可以到服务器只是nginx没监听 sudo netstat …

Linux 发送信号

进程可以通过系统调用kill函数向包括它本身在内的其他进程发送一个信号。如果程序没有发送该信号的权限&#xff0c;对kill函数的调用就将失败&#xff0c;失败的常见原因是目标进程由另一个用户所拥有。这个函数和shell命令完成相同的功能。 一、kill函数的定义 发送信号的k…

01- 中断

中断 中断1.1 NVIC中断优先级分组1.2 外部中断<1> 映射中断线<2> 设置中断触发方式<3> 编写中断服务函数外部中断常用的库函数&#xff1a;中断函数初始化外部中断的一般配置步骤&#xff1a;部分示例&#xff1a; 中断 1.1 NVIC中断优先级分组 《stm32中文…

自动驾驶——车辆动力学模型

/*lat_controller.cpp*/ namespace apollo { namespace control {using apollo::common::ErrorCode;//故障码 using apollo::common::Status;//状态码 using apollo::common::TrajectoryPoint;//轨迹点 using apollo::common::VehicleStateProvider;//车辆状态信息 using Matri…

分模块开发的意义及开发步骤

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaweb 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Maven进阶 一、分模块开发1.1分模块开发的意义1.2分模块开…

FlexTools plugin and 3dWindow plugin for SketchUp Crack

FlexTools v2.3.6 plugin for SketchUp 3dWindow v.4.5 plugin for SketchUp 建筑师和3D艺术家使用FlexTools创建SketchUp门、窗、楼梯和其他建筑元素&#xff0c;具有卓越的速度和控制水平。 SketchUp功能强大但易于使用的扩展。对于在施工图或建筑图中使用SketchUp的每个人…

Python 学习笔记——代码基础

目录 Python基础知识 变量 赋值 数据类型 print用法 print格式化输出 运算符 if-else 数据结构 元组 in运算符 列表 切片 [ : ] 追加 append() 插入 insert&#xff08;&#xff09; 删除 pop() 字典 循环 for循环 for循环应用——遍历 for循环应用——累加…

企业如何有效进行远程控制权限管理?向日葵权限管理能力解析

企业对于远程控制这一技术的管理&#xff0c;主要分为两部分&#xff0c;一种管理的目的是提升效率&#xff0c;另一种的目的是降低风险&#xff0c;我们这里着重聊聊后者。 企业管理远控行为&#xff0c;核心关键词是“权限”&#xff0c;通过不同的权限策略和能力&#xff0…

通信模块和光模块有什么区别?通信模块是光模块吗?

在现代科技高速发展的时代&#xff0c;通信技术扮演着举足轻重的角色&#xff0c;促进着全球信息的传递与交流。而在通信技术领域&#xff0c;通信模块与光模块是两个重要的组成部分。它们都在数据传输中发挥着关键作用&#xff0c;但又有着一些显著的区别。本文易天光通信将对…

一文看尽R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD详解

一文看尽R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD详解 以下六篇文章总结详细&#xff1a; 1. 一文读懂目标检测&#xff1a;R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD 2. 【深度学习】R-CNN 论文解读及个人理解 3、R-CNN论文详解 4、一文读懂Faster RCNN 5、学一百遍都…

Dockerfile概念、镜像原理、制作及案例讲解

1.Docker镜像原理 Linux文件操作系统讲解 2.镜像如何制作 3.Dockerfile概念 Docker网址&#xff1a;https://hub.docker.com 3.1 Dockerfile关键字 4.案例

基于YOLOv8模型的人体摔倒行为检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的人体摔倒行为检测系统可用于日常生活中检测与定位摔倒行人&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数…

Transformer是什么,Transformer应用

目录 Transformer应用 Transformer是什么 Transformer应用:循环神经网络 语言翻译:注重语句前后顺序 RNN看中单个特征; CNN:看中特征之间时序性 模型关注不同位置的能力 Transformer是什么 Transformer是一个利用注意力机制来提高模型训练速度的模型。关于注意力机…

分布式事务与解决方案

一、什么是分布式事务 首先我们知道本地事务是指事务方法中的操作只依赖本地数据库&#xff0c;可保证事务的ACID特性。而在分布式系统中&#xff0c;一个应用系统被拆分为多个可独立部署的微服务&#xff0c;在一个微服务的事务方法中&#xff0c;除了依赖本地数据库外&#…

R语言实现神经网络(1)

#R语言实现神经网络 library(neuralnet) library(caret) library(MASS) library(vcd) data(shuttle) str(shuttle)#因变量use; table1<-structable(windmagn~use,shuttle) mosaic(table1,shadingT) mosaic(use~errorvis,shuttle) prop.table(table(shuttle$use,shuttle$stab…

当你出差在外时,怎样轻松访问远程访问企业局域网象过河ERP系统?

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…

1191. K 次串联后最大子数组之和;2171. 拿出最少数目的魔法豆;1297. 子串的最大出现次数

1191. K 次串联后最大子数组之和 核心思想&#xff1a;贪心&#xff0c;如果k < 2 那么只需要按照求最大子数组和来求即可&#xff0c;如果k>2了&#xff0c;那么如果子数组的和大于0就把它加在一起&#xff0c;如果不大于0就不要这部分。 2171. 拿出最少数目的魔法豆 …

Octree八叉树python

原理 简单示例&#xff1a; 假设我们有以下一组三维点云数据&#xff1a; points [[0.1, 0.1, 0.1],[0.4, 0.1, 0.1],[0.1, 0.4, 0.1],[0.4, 0.4, 0.1],[0.1, 0.1, 0.4],[0.4, 0.1, 0.4],[0.1, 0.4, 0.4],[0.4, 0.4, 0.4], ] 我们可以使用八叉树将这些点云数据存储在三维空…

如何构造不包含字母和数字的webshell

利用不含字母与数字进行绕过 1.异或进行绕过 2.取反进行绕过 3.利用php语法绕过 利用不含字母与数字进行绕过 基本代码运行思路理解 <?php echo "A"^""; ?> 运行结果为! 我们可以看到&#xff0c;输出的结果是字符"!"。之所以会…

干翻Dubbo系列第十一篇:Dubbo常见协议与通信效率对比

文章目录 文章说明 一&#xff1a;协议 1&#xff1a;什么是协议 2&#xff1a;协议和序列化关系 3&#xff1a;协议组成 &#xff08;一&#xff09;&#xff1a;头信息 &#xff08;二&#xff09;&#xff1a;体信息 4&#xff1a;Dubbo3中常见的协议 5&#xff1a;…