129.【Spring 注解_IOC】

这篇具有很好参考价值的文章主要介绍了129.【Spring 注解_IOC】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


129.【Spring 注解_IOC】,spring,java,后端

(一)、组件注册

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

(1).无注解注入方式
  1. 在pom文件中加入spring-context依赖: xml文件和注解的包
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.12.RELEASE</version>
</dependency>
  1. 定义一个实体类
package com.jsxs.bean;

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

    private String name;
    private Integer age;

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

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

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

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

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

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

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

    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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 这两个组件标注的组件
129.【Spring 注解_IOC】,spring,java,后端

  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);
    }
}

我们发现我们的结果 只有我们通过配置
129.【Spring 注解_IOC】,spring,java,后端

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

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

129.【Spring 注解_IOC】,spring,java,后端
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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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));
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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));
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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>

129.【Spring 注解_IOC】,spring,java,后端
小结: 我们使用多实列的情况下,我们的组件并不会在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));
    }
}

因为懒加载的意思就是当我们使用的时候才回去创建实列,又因为是单实列的所以我们只会创建一次
129.【Spring 注解_IOC】,spring,java,后端

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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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);
        }

    }
}

129.【Spring 注解_IOC】,spring,java,后端

(2).ImportSelector ⭐

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

129.【Spring 注解_IOC】,spring,java,后端
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
     */
}

129.【Spring 注解_IOC】,spring,java,后端

(3). ImportBeanDefinitionRegistrar

129.【Spring 注解_IOC】,spring,java,后端
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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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 这个是实际上注入的组件
129.【Spring 注解_IOC】,spring,java,后端

(二)、组件的生命周期

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

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

129.【Spring 注解_IOC】,spring,java,后端

(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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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();
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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;
    }
}

129.【Spring 注解_IOC】,spring,java,后端
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);
        }

    }
}

129.【Spring 注解_IOC】,spring,java,后端

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

    /**
     * 使用@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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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"));
    }
}

结果:我们取到了我们外部的文件,但是因为是中文,所以出现中文乱码的操作
129.【Spring 注解_IOC】,spring,java,后端
129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(四)、自动装配

什么是自动装配?

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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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容器中有两个相同类型但不同名的组件。
129.【Spring 注解_IOC】,spring,java,后端
129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

3.@Autowried自动装配原理

129.【Spring 注解_IOC】,spring,java,后端

通过点击 @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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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);
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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

129.【Spring 注解_IOC】,spring,java,后端

129.【Spring 注解_IOC】,spring,java,后端

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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端

(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);
        }
    }
}

129.【Spring 注解_IOC】,spring,java,后端文章来源地址https://www.toymoban.com/news/detail-662564.html

到了这里,关于129.【Spring 注解_IOC】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring IOC @Configuration注解分析

    在使用SpringBoot开发时,最常用的注解有@Component、@Service、@Controller、@Configuration等。当类使用这些注解标记时,类会被Spring IOC容器管理,包括创建,填充属性和实例化。 但是Spring容器如何发现并将这些类放到容器进行管理呢? 今天这篇博客主要分析Spring如何处理@Configuratio

    2024年02月08日
    浏览(35)
  • Spring IOC相关注解运用——上篇

    目录 前言 一、@Component 二、@Repository、@Service、@Controller 三、@Scope 四、@Autowired 五、@Qualifier 六、@Value 1. 直接设置固定的属性值 2. 获取配置文件中的属性值 3. 测试结果 往期专栏文章相关导读  1. Maven系列专栏文章 2. Mybatis系列专栏文章 3. Spring系列专栏文章         注解配

    2024年02月02日
    浏览(43)
  • 【Spring篇】IOC/DI注解开发

    🍓系列专栏:Spring系列专栏 🍉个人主页:个人主页 目录 一、IOC/DI注解开发 1.注解开发定义bean  2.纯注解开发模式 1.思路分析 2.实现步骤 3.注解开发bean作用范围与生命周期管理 1.环境准备 2.Bean的作用范围 3.Bean的生命周期 4.注解开发依赖注入 1.环境准备 2.注解实现按照类型注入

    2024年02月03日
    浏览(76)
  • 11Spring IoC注解式开发(下)(负责注入的注解/全注解开发)

    负责注入的注解,常见的包括四个: @Value @Autowired @Qualifier @Resource 当属性的类型是简单类型时,可以使用@Value注解进行注入。 @Value注解可以出现在属性上、setter方法上、以及构造方法的形参上, 方便起见,一般直接作用在属性上. 配置文件开启包扫描: 测试程序: 三种方法都可

    2024年01月16日
    浏览(48)
  • 【Spring教程九】Spring框架实战:全面深入详解IOC/DI注解开发

    欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 IOC/DI配置管理第三方bean 加载properties文件》。 Spring的IOC/DI对应的配置开

    2024年02月03日
    浏览(49)
  • javaee spring 用注解的方式实现ioc

    spring核心依赖 spring配置文件

    2024年02月10日
    浏览(46)
  • 浅谈 Spring IOC 和 DI 以及 Spring 整合 Mybatis 的十四 个注解

    控制 : 指对对象的创建权 反转: 对象的创建由程序员在类中主动创建变为由Spring自动创建 Spring方式:所有的对象都是由Spring框架提前创建出来,存储到一个容器中,servlet需要Service了,就向Spring要一个 技术的作用 : 通过底层反射原理来 解开对象之间的耦合 注解 @Compone

    2024年02月16日
    浏览(37)
  • IDEA项目实践——Spring框架简介,以及IOC注解

    IDEA创建项目的操作步骤以及在虚拟机里面创建Scala的项目简单介绍 IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介 IDEWA项目实践——mybatis的一些基本原理以及案例 IDEA项目实践——动态SQL、关系映射、注解开发 文章目录 第1章 Spring 概述

    2024年02月14日
    浏览(48)
  • Spring IOC基于XML和注解管理Bean(二)

    Spring IOC基于XML和注解管理Bean(一) 2.9、实验八:p命名空间 引入p命名空间 引入p命名空间后,可以通过以下方式为bean的各个属性赋值 2.10、实验九:引入外部属性文件 ①加入依赖 ②创建外部属性文件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    2024年02月09日
    浏览(46)
  • Spring IOC基于XML和注解管理Bean(一)

    Spring IOC基于XML和注解管理Bean(二) IoC 是 Inversion of Control 的简写,译为“ 控制反转 ”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出 松耦合 、更优良的程序。 Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控

    2024年02月08日
    浏览(78)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包