在前一篇我们了解了 Spring IOC, Spring AOP 的强大,以及对我们编程范式,编程基础的影响。接下来我们一起来聊一下 Spring 基础概念。对于基础概念而言基本上都是属于那种字典类型的会有一定的枯燥程度,大佬文末见。
BeanDefinition 表示 Bean 的定义, BeanDefinition 中存在很多属性来描述 Bean 的特征。比如:
他的 Bean 属性方法关系图如下:
在 Spring 中,我们可以通过一下几种方式来定义 bean 1、xml 方式,可以通过 标签定义一个 bean 2、注解方式,可以通过 @Bean、@Component(@Service, @Controller,@Repository) 这几种方式,我们称为 申明式定义 Bean
我们还可以通过编程式定义 bean, 比如直接通过 BeanDefinition 创建, 比如:
public class BeanDefinitionTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//定义 BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//设置 scope
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
//设置bean类型
beanDefinition.setBeanClass(OrderService.class);
//设置懒加载
beanDefinition.setLazyInit(true);
//注册 bean
applicationContext.registerBeanDefinition("orderService", beanDefinition);
applicationContext.refresh();
System.out.println(applicationContext.getBean("orderService"));
}
}
class OrderService {
}
类比申明式事务,编程式事务,通过 、@Bean 、@Component 等申明方式所定义的 Bean , 最终都会被 Spring 解析为对应的 BeanDefinition 对象,并且放入 Spring 容器中。
BeanDefinitionReader 是 Spring 容器中提供的 BeanDefinition 读取器,用于将 Spring 的配置信息,转换为 BeanDefinition 。提供了4个实现类:
这些 BeanDefinitionReader 在我们使用 Spring 开的时候较少使用,在 Spring 源码中使用的比较多,相当于是 Spring 内部的基础设施。
可以直接把类转换为 BeanDefinition , 并且会解析类上的注解,例如:
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AnnotatedBeanDefinitionReaderTest.class);
AnnotatedBeanDefinitionReader annotationBeanDefinitionReader =
new AnnotatedBeanDefinitionReader(applicationContext);
annotationBeanDefinitionReader.register(UserService.class);
System.out.println(applicationContext.getBean(UserService.class));
XmlBeanDefinitionReader 可以读取 xml 中 spring 的配置信息获取 Bean 配置信息
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 是扫描器,但是它的作用和 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 表示 Bean 工厂,负责创建 Bean,提供获取 Bean 的 API。SpringApplicationContext 是 BeanFactory 的子类,通过ListableBeanFactory 继承了 BeanFactory 接口,还实现了 EnvironmentCapable 、MessageSource 、ResourcePatternResolver 。在 Spring 的源码中是这样定义的:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// ...
}
ApplicationContext 继承了 ListableBeanFactory 和 HierarchicalBeanFactory , 而 ListableBeanFactory 和 HierarchicalBeanFactory 都继承自 BeanFactory , 所以我们可以认为 ApplicationContext 继承了 BeanFactory, ApplicationContext 也是 BeanFactory 的子类,拥有 BeanFactory 支持的所有功能。
ApplicationContext 比 BeanFactory 更加强大, ApplicationContext 还实现了其他的基础接口。比如:MessageSource 国际化, ApplicationEventPublisher 事件发布, EnvironmentCapable 获取环境变量等等,关于 ApplicationContext 后面详细展开。
在 Spring 源码的实现中,当我们创建一个 ApplicationContext 时,也是创建 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 非常强大,我们可以查看它的继承关系:
从继承关系来看,它实现了很多接口,具备一下功能:
1、AliasRegistry: 支持别名功能,一个名字可以对应多个别名;
2、BeanDefinitionRegistry: 可以注册,保存,移除,获取某个 BeanDefinition;
3、SingletonBeanFactory:可以直接注册,获取一个单例 Bean;
4、SimpleAliasRegistry: 它是一个类,实现了 AliasRegistry 接口中所有的定义,支持别名功能;
5、ListableBeanFactory:在 BeanFactory 的基础上,增加了其他功能呢,可以获取所有的 BeanDefinition 的定义信息。
为应用程序提供配置的上下文。这在应用程序运行时是只读的,但如果实现支持,则可能会重新加载。ApplicationContext 提供一下功能:
org.springframework.core.io.ResourceLoader
接口;除了标准 BeanFactory 生命周期功能、ApplicationContext 实现检测和调用 ApplicationContextAware 对象 以及 ResourceLoaderAware、ApplicationEventPublisherware 和MessageSourceAware 对象。
下面我们一起来看一下,它的两个比较常用的实现类:
使用 AnnotationConfigApplicationContext 可以实现基于 Java 的配置类加载Spring的应用上下文。不用使用spring-context.xml
进行配置。也可以通过@Bean
@Component
等方式创建Bean, 相比 XML 配置, 更加便捷。
ClassPathXmlApplicationContext 是 spring 读取 xml 最常用的类。而我们一般操作的是它的接口ApplicationContext。BeanFactory和ApplicationContext区别不大,BeanFactory不在自动 BeanPostProcessor 和自动 BeanFactoryPostProcessor 上注册。使用中我们尽量用ApplicationContext。
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService UserSrv = (UserService)ctx.getBean("userService");
如果将ApplicationContext 改成 BeanFactory,是没有任何问题。AbstractApplicationContext有时也用这个。除了也继承自BeanFactory和ApplicationContext外,还有一个方法registerShutdownHook(),它会让你的Spring IoC容器关闭。当然如果在web应用的话,也会自动关闭。
Spring 国际化可以通过定义 MessageSource Bean 然后通过 ApplicationContext#getMessage 来获取国际化配置文件中配置的 message 值。
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
同时,因为 ApplicationContext 也拥有国际化功能,所以可以直接这么使用:
context.getMessage("test", null, new Locale("en"));
通常国内业务的项目很少使用,大公司或者海外项目使用比较多,会做多语言的文案内容处理,需要公司有专业的翻译团队或者外包团队,不然中式外语很容易出笑话。
ApplicationContext 还拥有资源加载的功能,加载的内存包括本地文件,和网络资源。也可以说是一个比较实用的工具 API,因为很多初学者搞不清楚相对路径,绝对路径,classpath 等。
比如,可以直接使用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);
ApplicationEvent 是 Spring 提供的事件驱动编程,也可以看作观察者模式的一个编程范本,支持同步监听和异步监听两种方式。
定义事件:
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source);
}
}
定义事件监听器:
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println("收到一个事件 ,,,,,");
}
}
调用程序:
@Configuration
public class ApplicationEventTest {
@Bean
public ApplicationListener applicationListener() {
return new TestListener();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationEventTest.class);
context.publishEvent(new TestEvent(new Object()));
}
}
Spring 容器启动过程中有很多启动过程的事件,我们可以通过这种方式来实现,在Spring 容器启动过后初始化一些内容:比如初始化系统参数到服务的本地内存等。不过我们需要注意的是 Spring 的事件机制只是一个本地事件,没有持久化机制。所以可靠性不能完全保证。
Spring 内部,有很多地方可能需要将 String 转换为其他类型,今天我们一起来学习一下 PropertyEditor、 ConversionService、TypeConverter 三种类型转换的使用。
PropertyEditor 是 JDK 提供的类型转换器,首先创建 bean :
@Service
public class OrderService {
@Value("orderVal")
private Order order;
public void test() {
System.out.println("test order : " + order);
}
}
创建类型转换器,将字符串转换为 Order 实例对象。
public class String2ObjectPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
Order order = new Order();
order.setName("haha");
order.setAge(12);
this.setValue(order);
}
}
注册转换器以及测试代码:
@Import({OrderService.class})
@Configuration
public class PropertyEditorTest {
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<>();
customEditors.put(Order.class, String2ObjectPropertyEditor.class);
CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
customEditorConfigurer.setCustomEditors(customEditors);
return customEditorConfigurer;
}
public static void main(String[] args) {
// 使用方式 1
String2ObjectPropertyEditor propertyEditor = new String2ObjectPropertyEditor();
propertyEditor.setAsText("1");
Object value = propertyEditor.getValue();
System.out.println(value);
// 使用方式 2
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PropertyEditorTest.class);
OrderService orderItemService = applicationContext.getBean(OrderService.class);
orderItemService.test();
}
}
ConversionService 是 Sprign 中提供的类型转换器,它比 PrppertyEditor 功能更加强大。定义转换器:
public class String2ObjectConversionService implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return
Objects.equals(sourceType.getType(), String.class)
&&
Objects.equals(targetType.getType(), Order.class);
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Order.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return new Order("haha", 32);
}
}
单独使用
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2ObjectConversionService());
Order order = conversionService.convert("1", Order.class);
System.out.println(order);
在 Spring 中使用:
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new String2ObjectConversionService()));
return conversionServiceFactoryBean;
}
Bean 的注入和调用代码:
// 测试和注入
@Service
public class OrderService {
//通过 @Value 注入
@Value("orderVal")
private Order order;
public void test() {
System.out.println("test order : " + order);
}
}
// 调用代码
ApplicationContext appliciton = new AnnotationConfigApplicationContext(ConvertTest.class);
OrderItemService orderItemService = appliciton.getBean(OrderItemService.class);
orderItemService.test();
TypeConverter 整合了 PropertyEditor 和 ConversionService, 在 Spring 内部使用:
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(Order.class, new String2ObjectPropertyEditor());
Order order = typeConverter.convertIfNecessary("orderVal", Order.class);
System.out.println(order);
比如在 AbstractBeanFacotry#adaptBeanInstance
中也有用到:
// AbstractBeanFacotry.java
<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
// Check if required type matches the type of the actual bean instance.
// 如果转换类型不为空,并且 bean 类型与目标类型不匹配
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// 尝试转换
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return (T) convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
OrderComparator 是 Spring 提供的一种比较器,可以根据 @Order 注解或者实现 Ordered 接口来进行比较,从而进行排序。如果说我们对一个 Bean 进行排序的话,我们可以在自动注入 List<BeanClass> beanList 的时候获取到默认排序的 Bean 集合。
举个例子:
public class B implements Ordered {
@Override
public int getOrder() {
return 2;
}
}
public class A implements Ordered {
@Override
public int getOrder() {
return 1;
}
}
public class OrderComparatorTest {
public static void main(String[] args) {
A a = new A();
B b = new B();
OrderComparator orderComparator = new OrderComparator();
System.out.println(orderComparator.compare(a, b)); // -1
List list = new ArrayList();
list.add(a);
list.add(b);
list.sort(orderComparator);
System.out.println(list); // a,b
}
}
另外,Spring 还提供了一个 OrderComparator 的子类:AnnotationAwareOrderComparator, 它支持 @Order
注解来指定 order 的值,比如:
@Order(1)
public class A1 {
}
@Order(1)
public class B1 {
}
public class OrderComparatorTest1 {
public static void main(String[] args) {
A1 a = new A1();
B1 b = new B1();
AnnotationAwareOrderComparator orderComparator = new AnnotationAwareOrderComparator();
System.out.println(orderComparator.compare(a, b)); // -1
List list = new ArrayList();
list.add(a);
list.add(b);
list.sort(orderComparator);
System.out.println(list); // a,b
}
}
BeanPostProessor 表示 bean 的后置处理器,我们可以定义一个或者多个 BeanPostProcessor , 比如通过如下的代码定义:
public class TestBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("postProcessBeforeInitialization userService");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("postProcessAfterInitialization userService");
}
return bean;
}
}
一个 BeanPostProcessor 可以在任意一个 Bean 的初始化之前以及初始化之后去做额外的一些用户的自定义逻辑。
BeanFactoryPostProcessor 表示 Bean 工厂的后置处理器,其实和 BeanPostProcessor 类似,BeanPostProcessor 是干涉 Bean 的创建过程, BeanFactoryPostProcessor 是干涉 BeanFactory 的创建过程,我们可以这样定义一个 BeanFactoryProcessor:
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("bean factory post processor");
}
}
我们可以在 postProcessBeanFactory() 方法中对 BeanFacorty 进行拓展。
上面提到,我们可以通过 BeanPostProcessor 来干涉 Spring 创建 Bean 的过程,但是如果我们想一个 Bean 完完全全由我们来创造,也是可以的,比如通过 FactoryBean 来实现。
@Component
public class TestFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
UserService userService = new UserService();
return userService;
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
通过上面这段代码,我们可以创造一个 UserService 对象,并且将它定义为一个 Bean, 但是通过这种方式定义的 Bean ,只会经过初始化后, 其他的 Spring 的生命周期不会经历,比如依赖注入。
通过 @Bean 也可以生成一个对象作为 Bean , 那么和 FactoryBean 的区别是什么呢?其实在很多场景下他两市可以替换的,但是在原理的层面来说,区别很明显, @Bean的 Bean会经过完整的 Bean的生命周期。
这两个 Filter 是 Spring 扫描过中用来过滤的,ExcludeFilter 表示排除过滤器,IncluderFilter 表示包含过滤器。比如一下配置,表示扫描 com.
这个包下返回的所有类, 但是排除 UserService 类 ,也就是算它上面所有的 @Component 注解也不会成为 Bean 。
@ComponentScan(value = "com.summer.test.service",
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)
})
public class AppConfig {
}
比如以下配置,就算 UserService 类上没有 @Component 注解,它也会呗扫描成一个 Bean
@ComponentScan(value = "com.summer.test.service",
includeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)
})
public class AppConfig {
}
FilterType 分为:
元数据读取器也是一个非常有意思的 API,我们可以通过它获取类的描述信息,比如可以读取自定义注解、某个类是否实现某接口、某个类是否存在某方法等。
常用的有以下几个类:
测试代码
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
// 构造 MetadataReader
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader("com.summer.test.service.UserService");
// 得到一个 ClassMetadata, 并且获取类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 获取一个 AnnotationMetadata, 并且获取该类上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
System.out.println(annotationMetadata.hasMetaAnnotation(Component.class.getName())); //true
System.out.println(annotationMetadata.hasAnnotation(Component.class.getName())); //false
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
// org.springframework.stereotype.Service
System.out.println(annotationType);
}
https://blog.csdn.net/knock_me/article/details/125728145