Spring 核心概念与使用技巧(上)

简介: Spring 核心概念与使用技巧

BeanDefinition


BeanDefinition 表示 Bean 的定义, BeanDefinition 中存在很多属性来描述 Bean 的特征。比如:


  • class, 表示 bean 的类型


  • scope, 表示 bean 的作用域,单例(singleton)或者原型(prototype


  • lazyInit, 表示 bean 是否懒加载


  • initMethodName, 表示 bean 的初始化需要执行的方法


  • destoryMethodName, 表示 bean 销毁时需要执行 bean 的方法


  • and more ...


在 Spring 中,我们可以通过一下几种方式来定义 bean 1、xml 方式,可以通过  标签定义一个 bean 2、注解方式,可以通过 @Bean、@Component(@Service, @Controller,@Repository) 这几种方式,我们称为** 申明式定义 Bean**

我们还可以通过编程式定义 bean, 那就是直接通过 BeanDefinition , 比如:


// 定义 BeanDefinition
AbstractBeanDefinition beanDefinition =
    BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
// 设置 scope
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
// 设置bean类型
beanDefinition.setBeanClass(BeanTest.class);
// 设置懒加载
beanDefinition.setLazyInit(true);
// 注册 bean
applicationContext.registerBeanDefinition("test", beanDefinition);


和申明式事务,编程式事务类似,通过  、@Bean 、@Component 等申明方式所定义的 Bean , 最终都会被 Spring 解析为对应的 BeanDefinition 对象,并且放入 Spring 容器中。


BeanDefinitionReader


BeanDefinitionReader 是 Spring 容器中提供的 BeanDefinition 读取器,这些 BeanDefinitionReader  在我们使用 Spring 开的时候较少使用,但是 Spring 源码中使用的比较多,相当于是 Spring 内部的基础设施。


AnnotationBeanDefinitionReader


可以直接把 类转换为 BeanDefinition , 并且会解析类上的注解,例如:


AnnotationConfigApplicationContext applicationContext =
    new AnnotationConfigApplicationContext(AnnotatedBeanDefinitionReaderTest.class);
AnnotatedBeanDefinitionReader annotationBeanDefinitionReader =
    new AnnotatedBeanDefinitionReader(applicationContext);
annotationBeanDefinitionReader.register(UserService.class);
System.out.println(applicationContext.getBean(UserService.class));


AnnotationBeanDefinitionReader


AnnotationConfigApplicationContext applicationContext =
    new AnnotationConfigApplicationContext(XmlBeanDefinitionReaderTest.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader =
    new XmlBeanDefinitionReader(applicationContext);
xmlBeanDefinitionReader.loadBeanDefinitions("classpath:spring-context.xml");
System.out.println(applicationContext.getBean(UserService.class));


ClassPathBeanDefinitionScanner


ClassPathBeanDefinitionScanner 是扫描器,但是它的作用和 BeanDefinitionReader 类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在 @Component 注解,那么就会把这个类解析为一个 BeanDefinition ,比如:


AnnotationConfigApplicationContext applicationContext =
    new AnnotationConfigApplicationContext(ClassPathBeanDefinitionScannerTest.class);
ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner =
    new ClassPathBeanDefinitionScanner(applicationContext);
classPathBeanDefinitionScanner.scan("com.summer.test.service");
System.out.println(applicationContext.getBean(UserService.class));


BeanFactory


BeanFactory 表示 Bean 工厂,所以很明显, BeanFactory 负责创建 Bean,并且提供获取 Bean 的 API。 而 SpringApplicationContext 是 BeanFactory 的子类,在 Spring 的源码中是这样定义的:


public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
    MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    // ...
}            


首先,在 Java  中,接口可以**多继承, **ApplicationContext 继承了 ListableBeanFactory 和 HierarchicalBeanFactory , 而 ListableBeanFactory 和 HierarchicalBeanFactory  都继承自 BeanFactory , 所以我们可以认为 ApplicationContext  继承了 BeanFactory ,相当于是苹果继承了水果,宝马汽车继承了汽车一样, ApplicationContext  也是 BeanFactory 的一种,用友了 BeanFactory 支持的所有功能,不过 ApplicationContext  比 BeanFactory  更加强大, ApplicationContext 还实现了其他的基础接口。 比如 MessageSource 表示国际化, ApplicationEventPublisher 表示事件发布, EnvironmentCapable 表示获取环境变量,等等,关于 ApplicationContext  后面详细讨论。


在 Spring 源码的实现中,当我们 new 一个 ApplicationContext 时,其底层会 new 一个 BeanFactory 出来, 相当于使用了 ApplicationContext  的某些方法时,比如 getBean() , 底层调用的 BeanFactory 的 getBean 。


在 Spring 源码中, BeanFactory 接口存在一个非常重要的实现类:DefaultLIsttableBeanFactory, 也是非常核心的。


所以,我们可以直接使用 DefaultLIsttableBeanFactory , 而不使用 ApplicationContext 的某个实现类:


DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
System.out.println(beanFactory.getBean("userService"));


DefaultLIsttableBeanFactory 非常强大,我们可以监看它的继承关系:

image.png


从继承关系来看,它实现了很多接口,具备一下功能: 1、AliasRegistry: 支持别名功能,一个名字可以对应多个别名。 2、BeanDefinitionRegistry: 可以注册,保存,移除,获取某个 BeanDefinition 3、SingletonBeanFactory: 可以直接注册,获取一个单例 Bean 4、SimpleAliasRegistry:  它是一个雷,实现了 AliasRegistry 接口中所有的定义,支持别名功能 5、ListableBeanFactory: 在 BeanFactory 的基础上,增加了其他功能呢,可以获取所有的 BeanDefinition 的定义信息。


ApplicationContext


AnnotationConfigApplicationContext


ClassPathXmlApplicationContext


国际化


先定义个 MessageSource:


@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasename("messages");
    return messageSource;
}


创建完这个 Bean , 我们可以在任何需要使用国际化的地方使用该 MessageSource 的 Bean 对象。 同时,因为 ApplicationContext 也拥有国际化功能,所以可以直接这么使用:


context.getMessage("test", null, new Locale("en"));


资源加载


ApplicationContext 还拥有资源加载的功能,比如,可以直接使用 ApplicationConext 获取某个文件的内容:


AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("file://C:\\a.txt")
System.out.println(resource.contextLength())


通过 ApplicationConext  来实现这个功能,可以提高我们的开发效率。 比如我们还可以这样使用:


AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("classpath:spring-context.xml")
System.out.println(resource.contextLength())
Resource resource2 = context.getResource("https://baidu.com");
System.out.println(resource2.getURL());


我们也可以获取多个资源


AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("classpath:spring-context.xml")
System.out.println(resource.contextLength())


获取运行时环境变量


Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);
Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);


也可以解析文件


@PropertySource("classpath:spring.properties")


可以让某一个 properties 文件添加到我们的环境变量中,可以通过一下的代码来获取:


String abc = context.getEnvironment().getProperty("abc", "1");
System.out.println(abc);


相关文章
|
13天前
|
Java 开发者 Spring
深入理解 Spring Boot 中的 @EnableAutoConfiguration 注解:概念与实践
【4月更文挑战第21天】在 Spring Boot 项目中,@EnableAutoConfiguration 注解是实现自动配置的核心,它可以根据项目的依赖和配置,自动地配置 Spring 应用程序中的 Bean
29 3
|
14天前
|
Java API 网络架构
深入理解 Spring Boot 中的 @RestController 注解:概念与实践
【4月更文挑战第20天】在现代Web开发中,创建RESTful服务已成为常态。Spring Boot通过提供@RestController注解,极大简化了REST API的开发过程。本篇博客旨在详细介绍@RestController的概念、优势以及在Spring Boot项目中的具体应用方法。
31 8
|
14天前
|
Java 开发者 Spring
Spring Framework 中的 @Autowired 注解:概念与使用方法
【4月更文挑战第20天】在Spring Framework中,@Autowired 注解是实现依赖注入(Dependency Injection, DI)的一种非常强大的工具。通过使用 @Autowired,开发者可以减少代码中的引用绑定,提高模块间的解耦能力
31 6
|
26天前
|
设计模式 监控 Java
深入浅出 Spring:核心概念和基本用法详解
深入浅出 Spring:核心概念和基本用法详解
24 0
|
14天前
|
XML Java 数据库
探索 Spring Boot 中的 @Configuration 注解:核心概念与应用
【4月更文挑战第20天】在 Spring Boot 项目中,@Configuration 注解扮演了一个关键角色,它标识一个类作为配置源,这些配置用于定义和管理 Spring 应用程序中的 Bean
39 7
|
5天前
|
安全 Java 测试技术
Spring Boot集成支付宝支付:概念与实战
【4月更文挑战第29天】在电子商务和在线业务应用中,集成有效且安全的支付解决方案是至关重要的。支付宝作为中国领先的支付服务提供商,其支付功能的集成可以显著提升用户体验。本篇博客将详细介绍如何在Spring Boot应用中集成支付宝支付功能,并提供一个实战示例。
20 2
|
5天前
|
Java 关系型数据库 数据库
Spring Boot多数据源及事务管理:概念与实战
【4月更文挑战第29天】在复杂的企业级应用中,经常需要访问和管理多个数据源。Spring Boot通过灵活的配置和强大的框架支持,可以轻松实现多数据源的整合及事务管理。本篇博客将探讨如何在Spring Boot中配置多数据源,并详细介绍事务管理的策略和实践。
25 3
|
4天前
|
XML Java API
Spring Boot 整合 LiteFlow 规则引擎:概念与实战
【4月更文挑战第30天】在现代软件开发中,规则引擎允许我们以声明式的方式定义业务逻辑和决策路径。LiteFlow 是一个轻量级、易于使用的组件式规则引擎,它可以与 Spring Boot 应用无缝整合。本文将介绍如何在 Spring Boot 项目中引入 LiteFlow,实现灵活的业务流程管理。
16 0
|
5天前
|
安全 Java 测试技术
利用Java反射机制提高Spring Boot的代码质量:概念与实战
【4月更文挑战第29天】Java反射机制提供了一种强大的方法来在运行时检查或修改类和对象的行为。在Spring Boot应用中,合理利用反射可以提高代码的灵活性和可维护性。本篇博客将探讨Java反射的核心概念,并展示如何通过反射提高Spring Boot项目的代码质量。
20 0
|
5天前
|
监控 Java 测试技术
Spring Boot与事务钩子函数:概念与实战
【4月更文挑战第29天】在复杂的业务逻辑中,事务管理是确保数据一致性和完整性的关键。Spring Boot提供了强大的事务管理机制,其中事务钩子函数(Transaction Hooks)允许开发者在事务的不同阶段插入自定义逻辑。本篇博客将详细探讨事务钩子函数的概念及其在Spring Boot中的应用。
16 1