129.【Spring 注解_IOC】(二)

简介: 129.【Spring 注解_IOC】
(2).注解扫描注入方式

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

package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */
@ComponentScan(value = "com.jsxs")
@Configuration
public class MyConfig {
    @Bean
    public Person person(){
        return new Person("李三",21);
    }
}

(3).指定扫描或不扫描的包 (过滤)
  1. 使用 @ComponentScan 进行操作扫描包 - (排除xxx)
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */
// 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
@ComponentScan(value = "com.jsxs",
        excludeFilters = {  // 这里是排除掉xxx
                @ComponentScan.Filter(
                        type = FilterType.ANNOTATION,
                        classes = {
                                Controller.class,
                                Service.class
                        }
                )
        })
@Configuration
public class MyConfig {
    @Bean
    public Person person() {
        return new Person("李三", 21);
    }
}

结果我们发现: 我们IOC容器中的组件中少我们指定的Controller 和 Service 这两个组件标注的组件

  1. 使用 @ComponentScans 进行扫描多个 @ComponentScan (不排除xxx)
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */
// 这里可以通过 @ComponentScans 配置多个 @@ComponentScan
    @ComponentScans(value = {
// 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
            @ComponentScan(value = "com.jsxs",
                    includeFilters = {  // 这里是只有包含这些组件的才被打印出来
                            @ComponentScan.Filter(
                                    type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}
                            )}, useDefaultFilters = false)  // 这里就相当于把所有的非includeFilters全部过滤掉,不显示(默认为true)
    })
@Configuration
public class MyConfig {
    @Bean
    public Person person() {
        return new Person("李三", 21);
    }
}

我们发现我们的结果 只有我们通过配置

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

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

1. 过滤的文件是这样写的

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

2. 配置文件是这样写的

package com.jsxs.config;
import com.jsxs.Mapper.BookMapper;
import com.jsxs.bean.Person;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
 * @Author Jsxs
 * @Date 2023/8/12 9:05
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig
 * @Description: TODO
 * @Version 1.0
 */
/**
 *  TODO: 1. ANNOTATION 按照注解 ; 2.  ASSIGNABLE_TYPE 按照给定的类型 3.CUSTOM 自定义规则
 */
// 1. 这里是一个数组,可以包含多个@ComponentScan
@ComponentScans(value = {
        //  2. 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
        @ComponentScan(value = "com.jsxs",
                // 3. 这里是一个数组,可以包含多个 Filter
                includeFilters = {  // 4. 这里是只有包含这些组件的才被打印出来
                        // 4.1 第一个Filter ⭐
                        @ComponentScan.Filter( // 5. 类型是注解 ; 要过滤的类文件
                                type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}
                        ),
                        // 4.2 第二个Filter ⭐
                        @ComponentScan.Filter(
                                type = FilterType.ASSIGNABLE_TYPE,classes = {BookMapper.class}
                        ),
                        // 4.3 第三个Filter ⭐
                        @ComponentScan.Filter(  // 5.指向我们自定义的过滤类信息
                                type = FilterType.CUSTOM,classes = {MyTypeFilter.class}
                        )
                }, useDefaultFilters = false)  // 这里就相当于把所有的非includeFilters全部过滤掉,不显示
})
@Configuration
public class MyConfig {
    @Bean
    public Person person() {
        return new Person("李三", 21);
    }
}

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

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

组件默认在IOC容器中是单实列的,也就是说我们在IOC容器中使用的组件都是同一个组件。

1. 进行编写我们的配置文件

package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {
    @Bean("person2")
    public Person person(){
        return new Person("张三2",22);
    }
}

2.测试类

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

(2).修改为多实列 (注解)
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {
    /**  1. singleton 但是列的
     *   2.prototype 多实列   (默认值)
     *   3. 同一次请求创建一个实列
     *   4. 同一个session创建一个实列
     */
    @Scope(value = "prototype")  // ⭐ 我们这在里修改为多实列的
    @Bean("person2")
    public Person person(){
        return new Person("张三2",22);
    }
}
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.通过我们的组件名获取我们指定的组件信息
        Person person = (Person)applicationContext.getBean("person2");
        Person person2 = (Person)applicationContext.getBean("person2");
        // 3.打印出我们的组件信息
        System.out.println(person);
        // 4.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        // 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件  ⭐
        System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
    }
}

(3).使用我们的XML文件进行实现多实列
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--     包自动扫描: 凡是带有 @Controller @Service @Repository @Component     -->
    <context:component-scan base-package="com.jsxs"/>
    <!--  通过Bean的方式进行我们的组件注入的操作  -->
    <bean id="person" class="com.jsxs.bean.Person" scope="prototype">
        <property name="name" value="李明"/>
        <property name="age" value="19"/>
    </bean>
</beans>

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

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

5.@Layz-bean懒加载

(1).懒加载

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

单实列 + 懒加载 ≠ 多实例

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

package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {
    /**  1. singleton 但是列的
     *   2.prototype 多实列   (默认值)
     *   3. 同一次请求创建一个实列
     *   4. 同一个session创建一个实列
     */
    @Scope(value = "prototype")  //⭐
    @Bean("person2")
    @Lazy  //⭐
    public Person person(){
        return new Person("张三2",22);
    }
}

2.进行测试

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

因为懒加载的意思就是当我们使用的时候才回去创建实列,又因为是单实列的所以我们只会创建一次

6.@Conditional 按照条件注册bean

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

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

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

WindowConditional.java

package com.jsxs.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 * @Author Jsxs
 * @Date 2023/8/13 19:18
 * @PackageName:com.jsxs.conditional
 * @ClassName: WindowConditional
 * @Description: TODO
 * @Version 1.0
 */
public class WindowConditional implements Condition {  //⭐
    /**
     *
     * @param context : 可以获取到上下文
     * @param metadata : 注解
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        if (environment.getProperty("os.name").contains("Windows")){
            return true;
        }
        return false;
    }
}

LinuxConditional.java

package com.jsxs.conditional;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 * @Author Jsxs
 * @Date 2023/8/13 19:18
 * @PackageName:com.jsxs.conditional
 * @ClassName: LinuxConditional
 * @Description: TODO  我们需要继承Condition这个接口
 * @Version 1.0
 */
public class LinuxConditional implements Condition {  //⭐
    /**
     *
     * @param context : 判断条件能使用的上下文(环境)
     * @param metadata : 注释信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 1. 能获取到IOC使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 2. 能获取到类加载器
        ClassLoader classLoader = context.getClassLoader();
        // 3. 获取我们的开发环境
        Environment environment = context.getEnvironment();
        // 4.获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        if (environment.getProperty("os.name").contains("Linux")){
            return true;
        }
        return false;
    }
}

MyConfig2.java

package com.jsxs.config;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
public class MyConfig2 {
    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})  //⭐
    @Bean("person01")
    public Person person01(){
        return new Person("张三01",33);
    }
    @Conditional(LinuxConditional.class)  // ⭐
    @Bean("person02")
    public Person person02(){
        return new Person("张三02",33);
    }
}

相关文章
|
2月前
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
125 1
|
2月前
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
2月前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
53 0
|
21天前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
119 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
8天前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
5天前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
15 4
|
9天前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
30 3
|
9天前
|
Java Spring 容器
Spring使用异步注解@Async正确姿势
Spring使用异步注解@Async正确姿势,异步任务,spring boot
|
8天前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
9天前
|
XML 前端开发 Java
控制spring框架注解介绍
控制spring框架注解介绍
下一篇
无影云桌面