Spring Framework 源码学习笔记(一)(下)

简介: Spring Framework 源码学习笔记(一)

FilterType是一个枚举类,默认是ANNOTATION,注解方式

image.png

修改BeanConfig代码,增加includeFilters(),只扫描com.citi包下面的@Controller,@Service注解标识的Bean,一定不要忘记useDefaultFilters = false

@Configuration
@ComponentScan(basePackages = "com.citi",
        includeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
        },
        useDefaultFilters = false)
public class BeanConfig {
}
复制代码

执行测试,控制台输出只包含了@Controller,@Service注解的Bean,@Componet和@Repository注解标识的类并没有被容器管理

image.png

Plus:为什么使用includeFilters时,要配置useDefaultFilters = false?

image.png

当useDefaultFilters = true时,进入到registerDefaultFilters()方法中

image.png

该方法中将@Component注解的Bean都加入到includeFilters中,而@Controller,@Service,@Repository都是基于@Component的注解,所有useDefaultFilters = true会导致设置是扫描@Controller和@Service注解的Bean不生效

使用excludeFilters(),将BeanConfig中includeFilters改为excludeFilters(),并且useDefaultFilters = true,执行测试,可以看出只包含了除了@Controller,@Service标注的Bean之外的其他Bean的实例化对象

image.png

使用FilterType枚举类中的ASSIGNABLE_TYPE进行过滤Bean,修改BeanConfig为如下,表示触PersonController和PersonService之外的其他Bean

@Configuration
@ComponentScan(basePackages = "com.citi",
        excludeFilters = {
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {PersonController.class, PersonService.class})
        },
        useDefaultFilters = true)
public class BeanConfig {
}
复制代码

image.png

使用自定义的FilterType,在config包下新增CustTypeFilter,继承TypeFilter

public class CustTypeFilter implements TypeFilter {
    /**
     * @param metadataReader 读取到当前正在扫描的类的信息
     * @param metadataReaderFactory 可以获取到其他任何类的信息
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // 获取当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // 获取当前正在扫描的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // 获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();
        // 获取类的名称
        String className = classMetadata.getClassName();
        // 扫描的类
        System.out.println("------>" + className);
        // 过滤条件,return true表示过滤掉符合这个条件的Bean
        if (className.contains("service")){
            return true;
        }
        return false;
    }
}
复制代码

image.png

除了@ComponentScan之外还可以添加@ComponentScans,也就是多个@ComponentScan

image.png

使用了两个@ComponentScan注解,一个是去除自定义的Bean,即bean id包含“service”字符串的Bean,另外一个使用Annotation 类型的Filter,去除@Controller注解标记的Bean

@ComponentScans({@ComponentScan(basePackages = "com.citi",
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {CustTypeFilter.class})
        },
        useDefaultFilters = true),
        @ComponentScan(basePackages = "com.citi",
                excludeFilters = {
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
                },
                useDefaultFilters = true)})
public class BeanConfig {
}
复制代码

这里控制台应该输出包含除了PeresonController和PersonService外的实例化对象,根据控制台打印可以看出配置的两个@ComponentScan都没有生效,这里还有待继续探索,

image.png

Section 04 - Bean的单实例和多实例

IoC容器不管是使用注解还是xml方式,默认都是单实例的,IoC容器初始化的时候就会被创建,多实例仅当bean被使用的时候才会创建 修改BeanConfi为

@Configuration
public class BeanConfig {
        @Bean
        public Person person(){
                Person person = new Person();
                person.setName("Stark");
                person.setAge(40);
                return person;
        }
}
复制代码

新增测试类SingleOrMultInstanceTest,执行testSingleBean()方法

public class SingleOrMultiInstanceTest {
    @Test
    public void testSingleBean(){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        Person person = (Person) context.getBean("person");
        Person person1 = (Person) context.getBean("person");
        System.out.println("是否为单实例:" + (person == person1));
    }
}
复制代码

查看输出结果,通过比较从容器中获取的两个bean是否为一个bean,默认是单实例

image.png

@Scope注解可以配置Bean为单实例或者多实例 @Scope源码

image.png

image.png

修改BeanConfig

@Configuration
public class BeanConfig {
        @Bean
        @Scope("prototype")
        public Person person(){
                Person person = new Person();
                person.setName("Stark");
                person.setAge(40);
                return person;
        }
}
复制代码

执行测试,此时已经为多实例

image.png

Section 05 - 懒加载@Lazy

修改BeanConfig,增加@Lazy注解,懒加载指针多单实例Bean,因为单实例是在容器初始化是就创建对象,增加@Lazy注解后,当调用getBean()获取实例化对象时容器才会实例化Bean 首先将BeanConfig中@Scope注解注释

@Configuration
public class BeanConfig {
        //@Lazy
        @Bean
        //@Scope("prototype")
        public Person person(){
                System.out.println("Bean被实例化");
                Person person = new Person();
                person.setName("Stark");
                person.setAge(40);
                return person;
        }
}
复制代码

新增LazyLoadTest,testLazyLoad()方法中只包含容器初始化的代码,执行该方法

public class LazyLoadTest {
    @Test
    public void testLazyLoad(){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        //Person person = (Person) context.getBean("person");
        //System.out.println(person);
    }
}
复制代码

查看控制台,打印了Bean被实例化,说明容器初始化是就执行了Bean实例化操作

image.png

放开BeanConfig中的@Lazy注解,再次执行,Bean没有被实例化

image.png

在LazyLoadTest类中的testLazyLoad()方法中增加获取Bean的代码

public class LazyLoadTest {
    @Test
    public void testLazyLoad(){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        Person person = (Person) context.getBean("person");
        System.out.println(person);
    }
}
复制代码

再次执行,结合上一次的执行结果,说明增加了@Lazy注解后,容器初始化是不在实例化Bean,而是在getBean时才会实例化Bean

image.png


相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
77 2
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
24天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
44 2
|
1月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
67 9
|
2月前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
43 9
|
1月前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
34 0
|
2月前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
28 1
|
2月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
109 2
|
2月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
247 1
|
2月前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
37 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现