Spring Configuration:@Import的用法和源码解析
Spring 3.0之后的@Configuration注解和注解配置体系革新了bean的配置方式。本文主要解析@Import的源码引用用法和源码实现。1. @Import的源码引用用法
配置类,如带有@Configuration注解的源码引用类,可作为bean注册起点。源码引用除了@Bean方法声明bean,源码引用opc client源码@Import注解允许批量注册相关bean。源码引用例如,源码引用WebMvcConfig通过@Import导入其他配置类,源码引用同时借助@EnableWebMvc导入另一配置类。源码引用2. 直接导入
用户可以通过@Import注解在配置类上导入一个或多个类,源码引用甚至可以嵌套在父类注解中,源码引用如WebMvcConfig导入的源码引用DelegatingWebMvcConfiguration。3. ImportBeanDefinitionRegistrar和ImportSelector
-
如@EnableAspectJAutoProxy通过ImportBeanDefinitionRegistrar实现,源码引用注册AnnotationAwareAspectJAutoProxyCreator。源码引用
-
@EnableTransactionManagement通过ImportSelector(如TransactionManagementConfigurationSelector)选择需要的事务配置类。
4. 源码解析
ConfigurationClassPostProcessor负责处理@Configuration类,通过ConfigurationClassParser解析配置类及其导入的类,然后由ConfigurationClassBeanDefinitionReader注册BeanDefinition。处理@Import时,通过深度优先搜索避免循环导入。 解析过程中,配置类的wp大前端源码递归导入需防止环形依赖,通过导入链映射表判断。此外,还考虑了内部配置类递归导入外部类的情况。5. ImportBeanDefinitionRegistrar和ImportSelector的行为
-
导入注册器和选择器时,会提前触发Aware接口方法,并在BeanDefinition注册时执行注册方法。
-
DeferredImportSelector处理时机独特,但处理逻辑与普通选择器类似,只是在解析末尾进行。
总结
@Configuration的@Import提供了丰富的导入方式,展现了灵活性。源码中的处理策略确保了解析过程的稳定性和效率,体现了Spring框架的精细设计和用户自定义的便捷性。Spring源码 1.源码的下载与编译(by Gradle)
为了获得Spring源码并成功编译,我们首先需要下载源码。方法之一是使用Git clone命令,前提是我们已安装Git。但要注意,最新版本可能需要JDK ,若需使用JDK 8,推荐选择较旧版本。GitHub上,瞳光全套源码最新稳定版本为5.2..RELEASE,这是一个GA(General Availability)版本,表示正式发布的版本,适合在生产环境中使用。如果你使用的是JDK 8,建议选择分支版本。
如果GitHub服务不可用或下载速度缓慢,可以考虑从其他资源库下载。例如,可以使用csdn提供的资源链接支持作者,或者直接从gitee下载源码。
下载源码后,导入IDEA并选择Gradle工程。IDEA会自动加载,但可能遇到一些报错。如果报错提示“POM relocation to an other version number is not fully supported in Gradle”,需要将xml-apis的版本号更改为1.0.b2。这可以通过在项目的build.gradle文件中添加指定版本的代码来实现。
加载并配置新模块后,可以通过新建测试类来进行验证。在build.gradle中添加配置,并在模块中新建文件,贷款资源源码包括一个启动类、一个配置类和一个实体类。记得刷新Gradle,进行测试。
测试结果应显示新建的实体类已被Spring容器加载。如果在测试中遇到问题,可以通过检查编译工具、编译器和项目结构来解决。确保使用本地Gradle路径、选择JDK 1.8版本,并在项目设置中选择正确的JDK版本。
Spring中ApplicationListener和ApplicationContext的使用
关于Spring的源码相关功能1引入ApplicationContextApplicationContext是Spring的一个核心接口,允许容器通过应用程序上下文环境创建,获取,管理bean.
publicinterfaceApplicationContextextendsEnvironmentCapable,ListableBeanFactory,HierarchicalBeanFactory,MessageSource,ApplicationEventPublisher,ResourcePatternResolver{ /***Returntheuniqueidofthisapplicationcontext.*@returntheuniqueidofthecontext,or{ @codenull}ifnone*/@NullableStringgetId();/***Returnanameforthedeployedapplicationthatthiscontextbelongsto.*@returnanameforthedeployedapplication,ortheemptyStringbydefault*/StringgetApplicationName();/***Returnafriendlynameforthiscontext.*@returnadisplaynameforthiscontext(never{ @codenull})*/StringgetDisplayName();/***Returnthetimestampwhenthiscontextwasfirstloaded.*@returnthetimestamp(ms)whenthiscontextwasfirstloaded*/longgetStartupDate();/***Returntheparentcontext,or{ @codenull}ifthereisnoparent*andthisistherootofthecontexthierarchy.*@returntheparentcontext,or{ @codenull}ifthereisnoparent*/@NullableApplicationContextgetParent();AutowireCapableBeanFactorygetAutowireCapableBeanFactory()throwsIllegalStateException;}ApplicationContext提供的功能:
访问应用程序组件的Bean工厂方法.从org.springframework.beans.factory.ListableBeanFactory继承而来.
publicinterfaceListableBeanFactoryextendsBeanFactory{ ......}通用方式加载文件资源的能力.从org.springframework.core.io.support.ResourcePatternResolver继承而来.
packageorg.springframework.core.io.support;importjava.io.IOException;importorg.springframework.core.io.Resource;importorg.springframework.core.io.ResourceLoader;publicinterfaceResourcePatternResolverextendsResourceLoader{ StringCLASSPATH_ALL_URL_PREFIX="classpath*:";Resource[]getResources(Stringvar1)throwsIOException;}向注册监听器发布事件的能力.从org.springframework.context.ApplicationEventPublisher继承而来.
@FunctionalInterfacepublicinterfaceApplicationEventPublisher{ defaultvoidpublishEvent(ApplicationEventevent){ publishEvent((Object)event);}voidpublishEvent(Objectevent);}解析消息的能力,支持国际化.从org.springframework.context.MessageSource继承而来.
publicinterfaceMessageSource{ @NullableStringgetMessage(Stringcode,@NullableObject[]args,@NullableStringdefaultMessage,Localelocale);StringgetMessage(Stringcode,@NullableObject[]args,Localelocale)throwsNoSuchMessageException;StringgetMessage(MessageSourceResolvableresolvable,Localelocale)throwsNoSuchMessageException;}从父上下文继承,后代上下文中的定义总是优先级.单个父上下文可以被整个web应用程序使用,而每个servlet都有自己独立于任何其他servlet的子上下文.
2关于ApplicationListener的说明2.1ApplicationListener简介ApplicationContext事件机制是属于设计模式中的观察者设计模式,通过ApplicationEvent类和ApplicationListener接口实现事件处理.
当容器中有一个ApplicationListener对象,当ApplicationContext发布ApplicationEvent事件时,ApplicationListener对象会被自动触发,需要由程序来控制.此外Spring中也内置了一下事件.
内置事件说明ContextRefreshedEventApplicationContext被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用refresh()方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有SingletonBean被预实例化,ApplicationContext容器已就绪可用ContextStartedEventConfigurableApplicationContext(ApplicationContext子接口)接口中的start()方法启动ApplicationContext时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的网站源码修改切换应用程序ContextStoppedEventConfigurableApplicationContext接口中的stop()停止ApplicationContext时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作ContextClosedEventConfigurableApplicationContext接口中的close()方法关闭ApplicationContext时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启RequestHandledEvent是web-specific事件,告诉所有beanHTTP请求已经被服务处理。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件2.2ApplicationListener案列1准备一个SpringBoot环境2创建一个自定义的监听器@ComponentpublicclassDemoApplicationListenerimplementsApplicationListener<ContextRefreshedEvent>{ @OverridepublicvoidonApplicationEvent(ContextRefreshedEventevent){ System.out.println(event);System.out.println("TestApplicationListener............................");}}根据上述可知,ContextRefreshedEvent内置事件,是ApplicationContext被初始化或刷新时会发布,即监听器可以收到回调信息.
3启动项目,查看日志3关于ApplicationContext的说明3.1ApplicationContext的简介从上述可知ApplicationContext具有发布事件的能力,是从ApplicationEventPublisher接口继承来的.而Spring中的事件使用,需要继承ApplicationEvent类或ApplicationContextEvent抽象类,抽象类中只有一个构造函数,且带有一个Object类型的参数作为事件源,且该事件源不能为null,因此我们需要在自己的构造函数中执行super(Object)。
publicclassEventObjectimplementsjava.io.Serializable{ privatestaticfinallongserialVersionUID=L;/***TheobjectonwhichtheEventinitiallyoccurred.*/protectedtransientObjectsource;/***ConstructsaprototypicalEvent.**@paramsourceTheobjectonwhichtheEventinitiallyoccurred.*@exceptionIllegalArgumentExceptionifsourceisnull.*/publicEventObject(Objectsource){ if(source==null)thrownewIllegalArgumentException("nullsource");this.source=source;}....}3.2ApplicationContext的案列3.2.1准备一个SpringBoot环境@SpringBootApplicationpublicclassApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(Application.class,args);testEvent();}//@Bean//publicFeignInterceptorfeignInterceptor(){ //returnnewFeignInterceptor();//}//测试事件publicstaticvoidtestEvent(){ ApplicationContextcontext=newAnnotationConfigApplicationContext(EventConfig.class);DemoEventdemoEvent=newDemoEvent(context,"小明",);context.publishEvent(demoEvent);}}3.2.2创建一个自定义的监听器@ComponentpublicclassDemo2ApplicationListenerimplementsApplicationListener<ApplicationEvent>{ @OverridepublicvoidonApplicationEvent(ApplicationEventevent){ //针对自定义事件做处理if(eventinstanceofDemoEvent){ System.out.println(event);DemoEventdemoEvent=(DemoEvent)event;System.out.println("姓名:"+demoEvent.getUsername()+",年龄:"+demoEvent.getAge());System.out.println("自定义DemoEvent事件............................");}}}3.2.3创建一个自定义的事件publicclassDemoEventextendsApplicationEvent{ privateStringusername;privateintage;/***CreateanewApplicationEvent.**@paramsourcetheobjectonwhichtheeventinitiallyoccurred(never{ @codenull})*/publicDemoEvent(Objectsource,Stringusername,intage){ super(source);this.username=username;this.age=age;}publicStringgetUsername(){ returnusername;}publicvoidsetUsername(Stringusername){ this.username=username;}publicintgetAge(){ returnage;}publicvoidsetAge(intage){ this.age=age;}}3.2.4启动项目,查看日志SpringBoot源码学习——SpringBoot自动装配源码解析+Spring如何处理配置类的
SpringBoot通过SPI机制,借助外部引用jar包中的META-INF/spring.factories文件,实现引入starter即可激活功能,简化手动配置bean,实现即开即用。
启动SpringBoot服务,通常使用Main方法启动,其中@SpringBootApplication注解包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan,自动装配的核心。
深入分析@SpringBootApplication,其实质是执行了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解的功能,简化了配置过程,强调了约定大于配置的思想。
SpringBoot的自动装配原理着重于研究如何初始化ApplicationContext,Spring依赖于ApplicationContext实现其功能,SpringApplication#run方法为初始化ApplicationContext的入口。
分析SpringApplication构造方法,SpringApplication.run(启动类.class, args) 实际调用的是该方法,其关键在于根据项目类型反射生成合适的ApplicationContext。
选择AnnotationConfigServletWebServerApplicationContext,此上下文具备启动Servlet服务器和注册Servlet或过滤器类型bean的能力。
准备刷新ApplicationContext,SpringBoot将主类注册到Spring容器中,以便@ConfigurationClassPostProcessor解析主类注解,发挥@Import、@ComponentScan的作用。
刷新ApplicationContext过程包括一系列前置准备,如将主类信息封装成AnnotatedGenericBeanDefinition,解析注解并调用BeanDefinitionCustomizer自定义处理。
解析配置类中的注解,通过BeanDefinitionRegistryPostProcessor和ConfigurationClassParser实现,筛选、排序候选者,并解析@Import注解实现自动装配。
增强配置类,ConfigurationClassPostProcessor对full模式的配置进行增强,确保@Import正确处理,CGLIB用于增强原配置类,确保生命周期完整,避免真正执行@Bean方法逻辑。
深入解析AutoConfigurationImportSelector实现自动装配,通过spring.boot.enableautoconfiguration设置开启状态,读取spring-autoconfigure-metadata.properties和META-INF/spring.factories文件,筛选并加载自动配置类。
SpringBoot读取.yml配置文件最常见的两种方式-源码及其在nacos的应用
当开发过程中遇到需要动态管理的配置值,如数据库密码和关键链接,通常会借助配置文件如.yml进行管理。其中,SpringBoot提供了两种常见的配置文件读取方式。第一种是使用@Value注解直接引用配置,但不支持动态更新,而推荐的方式是@ConfigurationProperties(prefix = "school"),它不仅更规范,且配合Nacos可以实现动态修改,无需重启项目即可生效。第一种方式
最简单的@Value注解,直接在application.yml中定义键值对,无需额外复杂操作,如在Controller中直接使用即可。通过调试确认可以读取配置值。第二种方式(推荐)
推荐的方式更为全面,尤其在Nacos中,可以实时更新配置。首先,修改YML文件以支持更多元的数据类型。然后,定义一个读取映射的类,如Spring官方的ServerProperties,它通过@ConfigurationProperties来读取配置。在Controller中测试,无需重启项目,修改配置后即可立即生效。 在Nacos上直接配置YML,读取的配置与推荐的School类一致。通过Controller获取并使用Postman进行测试,修改配置后,不重启项目,再次测试,即可见到实时更新的效果。 总结起来,虽然第二种方式比第一种更繁琐,但其动态更新和与Spring官方推荐的兼容性使其在生产环境中更具优势。这是一篇关于SpringBoot读取.yml配置文件的实践指南,由博客园作者小王写博客分享,原文链接在此,详情请参阅原文。Spring源码从入门到精通---@Import(五)
深入解析如何给容器注册bean
通过ComponentScan+注解如@Controller,@Service,@Compoment,@Repository实现自动扫描bean
@Bean+@Configuration定义导入第三方bean
利用@Import快速批量导入组件,优势在于简化配置
文章重点解析@Import的三种用法:直接导入容器、自定义importSelector实现、自定义ImportBeanDefinitionRegistrar手动注册
1)@import注解直接导入容器,id默认为全类名
2) 自定义importSelector类,返回需要注册的全类名数组
3) 实现ImportBeanDefinitionRegistrar接口,自定义组件注册和id
通过@Import源码,导入的实质是一个数组,允许批量导入多个类
演示通过import将组件如color和red导入容器,并展示容器中组件的打印
提供JUnit测试类,重复利用方法提取getDefinitionNames(),简化测试步骤
新增1)@Import基础使用部分,删除原有代码,便于理解@Import
运行示例,展示导入组件后的容器打印结果,突出import的优势
详细步骤:
2)自定义myImportSelector类实现ImportSelector,返回新增组件路径,结合扫描自定义类
结果展示:blue和yellow组件成功注册容器,验证自定义importSelect功能
3)实现ImportBeanDefinitionRegistrar接口,自定义组件名注册到容器
junit测试不变,运行结果:验证容器中包含red、yellow组件,满足自定义id需求
2024-12-24 00:11
2024-12-24 00:01
2024-12-23 23:38
2024-12-23 23:11
2024-12-23 23:11