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

目录
打赏
0
0
0
0
15
分享
相关文章
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
164 26
SpringBoot缓存注解使用
Spring Boot 提供了一套方便的缓存注解,用于简化缓存管理。通过 `@Cacheable`、`@CachePut`、`@CacheEvict` 和 `@Caching` 等注解,开发者可以轻松地实现方法级别的缓存操作,从而提升应用的性能和响应速度。合理使用这些注解可以大大减少数据库的访问频率,优化系统性能。
215 89
Spring MVC常用的注解
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中 的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 @Controller:控制器的注解,表示是表现层,不能用用别的注解代替 @RestController : 组合注解 @Conntroller + @ResponseBody @GetMapping , @PostMapping , @Put
Spring Boot的核心注解是哪个?他由哪几个注解组成的?
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 : ● @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能; ● @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项 ● @ComponentScan:Spring组件扫描
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
SpringBoot+@Async注解一起用,速度提升
本文介绍了异步调用在高并发Web应用性能优化中的重要性,对比了同步与异步调用的区别。同步调用按顺序执行,每一步需等待上一步完成;而异步调用无需等待,可提升效率。通过Spring Boot示例,使用@Async注解实现异步任务,并借助Future对象处理异步回调,有效减少程序运行时间。
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
209 73
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
127 69
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
21 0
|
1月前
|
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
73 16