国外做健康的网站,温岭专业营销型网站建设地址,网站建设教程网哪个好,如何去掉网站后缀wordpress你好#xff0c;我是柳岸花开。 在当今快速发展的软件开发领域#xff0c;各种技术层出不穷#xff0c;但有一项技术以其卓越的设计、灵活的配置和广泛的应用#xff0c;始终屹立在开发者的工具箱中——这就是Spring框架。自2003年首次发布以来#xff0c;Spring已经成为J… 你好我是柳岸花开。 在当今快速发展的软件开发领域各种技术层出不穷但有一项技术以其卓越的设计、灵活的配置和广泛的应用始终屹立在开发者的工具箱中——这就是Spring框架。自2003年首次发布以来Spring已经成为Java企业级应用开发的事实上的标准。无论是初出茅庐的新手还是经验丰富的老手都无法忽视Spring框架在构建高效、可维护的软件系统中的关键作用。 本文将深入探讨Spring框架的底层架构解析其核心概念帮助读者更好地理解和运用这一强大的工具。我们将从Spring的设计理念出发逐步展开对依赖注入DI、面向切面编程AOP、模块化和声明式事务管理等关键特性的讨论。通过本文你将能够洞察Spring的工作原理掌握其核心概念从而在实际开发中更加得心应手。 在开始之前让我们先来简单回顾一下Spring框架的历史。Spring的诞生源于对企业级应用开发中复杂性的深刻理解。开发者Rod Johnson在面对繁琐的配置和组件管理时提出了一种新的解决方案即通过简化对象的创建、配置和组装过程来提高开发效率和代码质量。这一理念最终孕育出了Spring框架它通过提供一套全面的编程和配置模型使得开发者能够轻松构建复杂的应用程序。 随着时间的推移Spring框架不断演进引入了诸如AOP、事务管理等高级特性进一步扩展了其功能范围。但不论如何变化Spring的核心始终围绕着简化开发和提升效率这一主题。接下来我们就将逐一剖析这些核心概念揭开Spring框架的神秘面纱。 BeanDefinition BeanDefinition表示Bean定义BeanDefinition中存在很多属性用来描述一个Bean的特点。比如 class表示Bean类型 scope表示Bean作用域单例或原型等 lazyInit表示Bean是否是懒加载 initMethodName表示Bean初始化时要执行的方法 destroyMethodName表示Bean销毁时要执行的方法 在Spring中我们经常会通过以下几种方式来定义Bean bean/ Bean Component(Service,Controller) 这些我们可以称之申明式定义Bean。 我们还可以编程式定义Bean那就是直接通过BeanDefinition比如 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);// 生成一个BeanDefinition对象并设置beanClass为User.class并注册到ApplicationContext中AbstractBeanDefinition beanDefinition BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(User.class);context.registerBeanDefinition(user, beanDefinition);System.out.println(context.getBean(user)); 我们还可以通过BeanDefinition设置一个Bean的其他属性 beanDefinition.setScope(prototype); // 设置作用域beanDefinition.setInitMethodName(init); // 设置初始化方法beanDefinition.setLazyInit(true); // 设置懒加载 和申明式事务、编程式事务类似通过 bean/BeanComponent等申明式方式所定义的Bean最终都会被Spring解析为对应的BeanDefinition对象并放入Spring容器中。 BeanDefinitionReader 接下来我们来介绍几种在Spring源码中所提供的BeanDefinition读取器BeanDefinitionReader这些BeanDefinitionReader在我们使用Spring时用得少但在Spring源码中用得多相当于Spring源码的基础设施。 AnnotatedBeanDefinitionReader 可以直接把某个类转换为BeanDefinition并且会解析该类上的注解比如 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader new AnnotatedBeanDefinitionReader(context);// 将User.class解析为BeanDefinitionannotatedBeanDefinitionReader.register(User.class);System.out.println(context.getBean(user)); 注意它能解析的注解是ConditionalScope、Lazy、Primary、DependsOn、Role、Description XmlBeanDefinitionReader 可以解析 bean/标签 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);XmlBeanDefinitionReader xmlBeanDefinitionReader new XmlBeanDefinitionReader(context);int i xmlBeanDefinitionReader.loadBeanDefinitions(spring.xml);System.out.println(context.getBean(user)); ClassPathBeanDefinitionScanner ClassPathBeanDefinitionScanner是扫描器但是它的作用和BeanDefinitionReader类似它可以进行扫描扫描某个包路径对扫描到的类进行解析比如扫描到的类上如果存在Component注解那么就会把这个类解析为一个BeanDefinition比如 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();context.refresh();ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(context);scanner.scan(com.bob);System.out.println(context.getBean(userService)); BeanFactory BeanFactory表示Bean工厂所以很明显BeanFactory会负责创建Bean并且提供获取Bean的API。 而ApplicationContext是BeanFactory的一种在Spring源码中是这么定义的 public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { ...} 首先在Java中接口是可以多继承的我们发现ApplicationContext继承了ListableBeanFactory和HierarchicalBeanFactory而ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory所以我们可以认为ApplicationContext继承了BeanFactoryApplicationContext也是BeanFactory的一种拥有BeanFactory支持的所有功能不过ApplicationContext比BeanFactory更加强大ApplicationContext还基础了其他接口也就表示ApplicationContext还拥有其他功能比如MessageSource表示国际化ApplicationEventPublisher表示事件发布EnvironmentCapable表示获取环境变量等等关于ApplicationContext后面再详细讨论。 在Spring的源码实现中当我们new一个ApplicationContext时其底层会new一个BeanFactory出来当使用ApplicationContext的某些方法时比如getBean()底层调用的是BeanFactory的getBean()方法。 在Spring源码中BeanFactory接口存在一个非常重要的实现类是DefaultListableBeanFactory也是非常核心的。 所以我们可以直接来使用DefaultListableBeanFactory而不用使用ApplicationContext的某个实现类比如 DefaultListableBeanFactory beanFactory new DefaultListableBeanFactory();AbstractBeanDefinition beanDefinition BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(User.class);beanFactory.registerBeanDefinition(user, beanDefinition);System.out.println(beanFactory.getBean(user)); 它实现了很多接口表示它拥有很多功能 AliasRegistry支持别名功能一个名字可以对应多个别名 BeanDefinitionRegistry可以注册、保存、移除、获取某个BeanDefinition BeanFactoryBean工厂可以根据某个bean的名字、或类型、或别名获取某个Bean对象 SingletonBeanRegistry可以直接注册、获取某个 单例Bean SimpleAliasRegistry它是一个类实现了AliasRegistry接口中所定义的功能支持别名功能 ListableBeanFactory在BeanFactory的基础上增加了其他功能可以获取所有BeanDefinition的beanNames可以根据某个类型获取对应的beanNames可以根据某个类型获取{类型对应的Bean}的映射关系 HierarchicalBeanFactory在BeanFactory的基础上添加了获取父BeanFactory的功能 DefaultSingletonBeanRegistry它是一个类实现了SingletonBeanRegistry接口拥有了直接注册、获取某个 单例Bean的功能 ConfigurableBeanFactory在HierarchicalBeanFactory和SingletonBeanRegistry的基础上添加了设置父BeanFactory、类加载器表示可以指定某个类加载器进行类的加载、设置Spring EL表达式解析器表示该BeanFactory可以解析EL表达式、设置类型转化服务表示该BeanFactory可以进行类型转化、可以添加BeanPostProcessor表示该BeanFactory支持Bean的后置处理器可以合并BeanDefinition可以销毁某个Bean等等功能 FactoryBeanRegistrySupport支持了FactoryBean的功能 AutowireCapableBeanFactory是直接继承了BeanFactory在BeanFactory的基础上支持在创建Bean的过程中能对Bean进行自动装配 AbstractBeanFactory实现了ConfigurableBeanFactory接口继承了FactoryBeanRegistrySupport这个BeanFactory的功能已经很全面了但是不能自动装配和获取beanNames ConfigurableListableBeanFactory继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory AbstractAutowireCapableBeanFactory继承了AbstractBeanFactory实现了AutowireCapableBeanFactory拥有了自动装配的功能 DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口所以DefaultListableBeanFactory的功能很强大 ApplicationContext 上面有分析到ApplicationContext是个接口实际上也是一个BeanFactory不过比BeanFactory更加强大比如 HierarchicalBeanFactory拥有获取父BeanFactory的功能 ListableBeanFactory拥有获取beanNames的功能 ResourcePatternResolver资源加载器可以一次性获取多个资源文件资源等等 EnvironmentCapable可以获取运行时环境没有设置运行时环境功能 ApplicationEventPublisher拥有广播事件的功能没有添加事件监听器的功能 MessageSource拥有国际化功能 我们先来看ApplicationContext两个比较重要的实现类 AnnotationConfigApplicationContext ClassPathXmlApplicationContext AnnotationConfigApplicationContext ConfigurableApplicationContext继承了ApplicationContext接口增加了添加事件监听器、添加BeanFactoryPostProcessor、设置Environment获取ConfigurableListableBeanFactory等功能 AbstractApplicationContext实现了ConfigurableApplicationContext接口 GenericApplicationContext继承了AbstractApplicationContext实现了BeanDefinitionRegistry接口拥有了所有ApplicationContext的功能并且可以注册BeanDefinition注意这个类中有一个属性(DefaultListableBeanFactory beanFactory) AnnotationConfigRegistry可以单独注册某个为类为BeanDefinition可以处理该类上的 Configuration注解已经可以处理 Bean注解 同时可以扫描 AnnotationConfigApplicationContext继承了GenericApplicationContext实现了AnnotationConfigRegistry接口拥有了以上所有的功能 ClassPathXmlApplicationContext 它也是继承了AbstractApplicationContext但是相对于AnnotationConfigApplicationContext而言功能没有AnnotationConfigApplicationContext强大比如不能注册BeanDefinition 国际化 先定义一个MessageSource: Beanpublic MessageSource messageSource() { ResourceBundleMessageSource messageSource new ResourceBundleMessageSource(); messageSource.setBasename(messages); return messageSource;} 有了这个Bean你可以在你任意想要进行国际化的地方使用该MessageSource。 同时因为ApplicationContext也拥有国家化的功能所以可以直接这么用 context.getMessage(test, null, new Locale(en_CN)) 资源加载 ApplicationContext还拥有资源加载的功能比如可以直接利用ApplicationContext获取某个文件的内容 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);Resource resource context.getResource(file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java);System.out.println(resource.contentLength()); 还比如可以 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);Resource resource context.getResource(file://D:\\IdeaProjects\\spring-framework-5.3.10\\tuling\\src\\main\\java\\com\\zhouyu\\service\\UserService.java);System.out.println(resource.contentLength());System.out.println(resource.getFilename());Resource resource1 context.getResource(https://www.baidu.com);System.out.println(resource1.contentLength());System.out.println(resource1.getURL());Resource resource2 context.getResource(classpath:spring.xml);System.out.println(resource2.contentLength());System.out.println(resource2.getURL()); 还可以一次性获取多个 Resource[] resources context.getResources(classpath:com/zhouyu/*.class);for (Resource resource : resources) { System.out.println(resource.contentLength()); System.out.println(resource.getFilename());} 获取运行时环境 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);MapString, Object systemEnvironment context.getEnvironment().getSystemEnvironment();System.out.println(systemEnvironment);System.out.println();MapString, Object systemProperties context.getEnvironment().getSystemProperties();System.out.println(systemProperties);System.out.println();MutablePropertySources propertySources context.getEnvironment().getPropertySources();System.out.println(propertySources);System.out.println();System.out.println(context.getEnvironment().getProperty(NO_PROXY));System.out.println(context.getEnvironment().getProperty(sun.jnu.encoding));System.out.println(context.getEnvironment().getProperty(zhouyu)); 注意可以利用 PropertySource(classpath:spring.properties) 来使得某个properties文件中的参数添加到运行时环境中 事件发布 先定义一个事件监听器 Beanpublic ApplicationListener applicationListener() { return new ApplicationListener() { Override public void onApplicationEvent(ApplicationEvent event) { System.out.println(接收到了一个事件); } };} 然后发布一个事件 context.publishEvent(bob); BeanPostProcessor BeanPostProcess表示Bena的后置处理器我们可以定义一个或多个BeanPostProcessor比如通过一下代码定义一个BeanPostProcessor Componentpublic class BobBeanPostProcessor implements BeanPostProcessor { Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (userService.equals(beanName)) { System.out.println(初始化前); } return bean; } Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (userService.equals(beanName)) { System.out.println(初始化后); } return bean; }} 一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑当然我们可以通过判断beanName来进行针对性处理针对某个Bean或某部分Bean。 我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。 BeanFactoryPostProcessor BeanFactoryPostProcessor表示Bean工厂的后置处理器其实和BeanPostProcessor类似BeanPostProcessor是干涉Bean的创建过程BeanFactoryPostProcessor是干涉BeanFactory的创建过程。比如我们可以这样定义一个BeanFactoryPostProcessor Componentpublic class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor { Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println(加工beanFactory); }} 我们可以在postProcessBeanFactory()方法中对BeanFactory进行加工。 FactoryBean 上面提到我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程但是如果我们想一个Bean完完全全由我们来创造也是可以的比如通过FactoryBean Componentpublic class BobFactoryBean implements FactoryBean { Override public Object getObject() throws Exception { UserService userService new UserService(); return userService; } Override public Class? getObjectType() { return UserService.class; }} 通过上面这段代码我们自己创造了一个UserService对象并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean只会经过初始化后其他Spring的生命周期步骤是不会经过的比如依赖注入。 通过Bean也可以自己生成一个对象作为Bean那么和FactoryBean的区别是什么呢其实在很多场景下他俩是可以替换的但是站在原理层面来说的区别很明显Bean定义的Bean是会经过完整的Bean生命周期的。 ExcludeFilter和IncludeFilter 这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器IncludeFilter表示包含过滤器。 比如以下配置表示扫描com.bob这个包下面的所有类但是排除UserService类也就是就算它上面有Component注解也不会成为Bean。 ComponentScan(value com.bob, excludeFilters {ComponentScan.Filter( type FilterType.ASSIGNABLE_TYPE, classes UserService.class)}.)public class AppConfig {} 再比如以下配置就算UserService类上没有Component注解它也会被扫描成为一个Bean。 ComponentScan(value com.bob, includeFilters {ComponentScan.Filter( type FilterType.ASSIGNABLE_TYPE, classes UserService.class)})public class AppConfig {} FilterType分为 ANNOTATION表示是否包含某个注解 ASSIGNABLE_TYPE表示是否是某个类 ASPECTJ表示否是符合某个Aspectj表达式 REGEX表示是否符合某个正则表达式 CUSTOM自定义 在Spring的扫描逻辑中默认会添加一个AnnotationTypeFilter给includeFilters表示默认情况下Spring扫描过程中会认为类上有Component注解的就是Bean。 MetadataReader、ClassMetadata、AnnotationMetadata 在Spring中需要去解析类的信息比如类名、类中的方法、类上的注解这些都可以称之为类的元数据所以Spring中对类的元数据做了抽象并提供了一些工具类。 MetadataReader表示类的元数据读取器默认实现类为SimpleMetadataReader。比如 public class Test { public static void main(String[] args) throws IOException { SimpleMetadataReaderFactory simpleMetadataReaderFactory new SimpleMetadataReaderFactory(); // 构造一个MetadataReader MetadataReader metadataReader simpleMetadataReaderFactory.getMetadataReader(com.bob.service.UserService); // 得到一个ClassMetadata并获取了类名 ClassMetadata classMetadata metadataReader.getClassMetadata(); System.out.println(classMetadata.getClassName()); // 获取一个AnnotationMetadata并获取类上的注解信息 AnnotationMetadata annotationMetadata metadataReader.getAnnotationMetadata(); for (String annotationType : annotationMetadata.getAnnotationTypes()) { System.out.println(annotationType); } }} 需要注意的是SimpleMetadataReader去解析类时使用的ASM技术。 为什么要使用ASM技术Spring启动的时候需要去扫描如果指定的包路径比较宽泛那么扫描的类是非常多的那如果在Spring启动时就把这些类全部加载进JVM了这样不太好所以使用了ASM技术。 本文由 mdnice 多平台发布