BeanDefinition
BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。
比如:
- class: 表示bean类型 ```java 为什么这里是Object,而不是Class<?>呢? 因为这里还没有加载,只是通过ASM技术去解析了这个类,并没有去解析, 只是把这个类的名字设置给了BeanDefinition的属性,当创建这个Bean的时候, 才会去真正的加载,所以这里使用的是Object
private volatile Object beanClass;
- scope: 表示bean作用域,有single、prototype、request、session、global
- lazyInit: 表示Bean是否是懒加载的
- initMethodName: 表示Bean初始化时要执行的方法
- destoryMethodName: 表示Bean销毁时要执行的方法
- 等等
在Spring中,我们经常会通过声明式定义Bean:
- bean标签
- @Bean
- @Component、@Service、@Controller
我们也可以使用编程式定义Bean,那就是直接通过BeanDefinition
```java
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 生成一个beanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
// 设置beanClass
beanDefinition.setBeanClass(User.class);
// 设置作用域
beanDefinition.setScope("prototype");
// 设置初始化方法
beanDefinition.setInitMethodName("init");
// 设置是否懒加载
beanDefinition.setLazyInit(true);
// 注册beanDefinition
context.registerBeanDefinition("user", beanDefinition);
System.out.println(context.getBean("user"));
这个和声明式事务、编程式事务类似,通过bean标签、@Bean等声明式所定义的Bean,最终都会被Spring解析为对应的BeanDefinition对象,并且放入Spring容器中。
BeanDefinitionReader
AnnotatedBeanDefinitionReader
可以直接把某个类转换成BeanDefinition,并且会解析该类上的注解
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析成BeanDefinition
reader.register(User.class);
System.out.println(context.getBean("user"));
==注意==: 它能解析的注解是: @Conditional、@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
XmlBeanDefinitionReader
可以解析Bean标签
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
int i = reader.loadBeanDefinitions("spring.xml");
System.out.println(i);
System.out.println(context.getBean("user"));
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("linc.cool");
System.out.println(context.getBean("userService"));
BeanFactory
BeanFactory表示Bean工厂,BeanFactory会负责创建Bean,并且提供获取Bean的API. 而ApplicationContext是BeanFactory的一种
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
...
}
ApplicationContext继承了ListableBeanFactory和HierarchialBeanFactory,而ListableBeanFactoru和HiearachialBeanFactory都继承至BeanFactory,所以我们可以认为ApplicationContext继承了BeanFactory.不过,ApplicationContext比BeanFactory更加强大,ApplicationContext还继承了其它接口,也就表示了ApplicationContext还拥有其它功能,比如MessageSource表示国际化、ApplicationEventPublisher表示事件发布、EnvironmentCapable表示获取环境变量等.
在Spring的源码实现中,当我们new一个ApplicationContext的时候,其底层都会new一个BeanFactory出来,当使用ApplicationContext的某些方法的时候,比如getBean,底层会调用BeanFactory的getBean.
在Spring源码中,BeanFactory接口存在一个非常重要的实现类是DefaultListableBeanFactory.
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanFactory.registerBeanDefinition("user", beanDefinition);
System.out.println(beanFactory.getBean("user"));
DefaultListableBeanFactory类图
- AliasRegistry: 支持别名功能,一个名字可以对应多个别名
- BeanDefitionRegistry: 可以注册、保存、移除、获取某个BeanDefinition
- BeanFactory: Bean工厂,可以根据某个Bean的名字、或类型、或别名获取某个Bean对象
- SingletonBeanRegistry: 可以直接注册、获取某个单例Bean
- SimpleAliasRegistry: 实现了AliasRegistry接口中所定义的功能,支持别名功能
- ListableBeanFactory: 在BeanFactory的基础上,增加了其它功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取到对应的beanNames,可以根据某个类型获取 类型与对应的Bean的映射关系
- HierachicalBeanFactory: 在BeanFactory的基础上,添加了获取父BeanFactory的功能
- DefaultSingletonBeanRegistry: 实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
- ConfigurableBeanFactory: 在HierachicalBeanFactory和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: 拥有广播事件的功能(没有添加事件监听器的功能)
-
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
在resource目录下定义国际化文件messages_en_CN.properties、messages_en.properties messages_en_CN.properties/** * 设置国际化 */ @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMess messageSource.setBasename("messages"); messageSource.setDefaultEncoding("utf8"); return messageSource; }
messages_en.propertiesfruit.apple=苹果
进行使用国际化fruit.apple=apple
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); String enCn = context.getMessage("fruit.apple", null, new Locale("en_CN")); System.out.println(enCn);
苹果
资源加载
ApplicationContext还拥有资源加载的功能,比如: 可以直接利用ApplicationContext获取某个文件的内容 ```java AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Resource resource1 = context.getResource(“file:/Users/linc/Desktop/dev/codes/java/deep/spring-framework-5.3.10/linc-day01/src/main/java/linc/cool/config/AppConfig.java”); System.out.println(resource1.contentLength());
Resource resource2 = context.getResource(“https://www.baidu.com“); System.out.println(resource2.contentLength());
Resource resource3 = context.getResource(“classpath:spring.xml”); System.out.println(resource3.contentLength());
Resource[] resource4 = context.getResources(“classpath:linc/cool/*.class”); System.out.println(resource4.length);
<a name="BsCGz"></a>
## 获取运行时环境
```java
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Map<String, Object> sysEnvMap = context.getEnvironment().getSystemEnvironment();
System.out.println(sysEnvMap);
Map<String, Object> sysPropertiesMap = context.getEnvironment().getSystemProperties();
System.out.println(sysPropertiesMap);
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);
System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("Dfile.encoding"));
==注意==可以利用 在resource目录下加一个spring.properties的配置文件
NO_PROXY=yes
在配置类加上
@PropertySource("classpath:spring.properties")
事件发布
定义一个事件监听器
/**
* 事件监听器
*/
@Bean
public ApplicationListener<?> applicationListener() {
return event -> {
System.out.println("接收到一个事件: " + event);
};
}
然后发布一个事件
context.publishEvent("xxx");
@Component
public class MyPublishEventBean implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public void test() {
context.publishEvent("myEvent");
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyPublishEventBean myPublishEventBean = context.getBean(MyPublishEventBean.class);
myPublishEventBean.test();
类型转化
在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景,后续看源码的过程中会遇到很多
PropertyEditor
PropertyEditor是JDK中提供的类型转化工具类
public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
User user = new User();
user.setName(text);
this.setValue(user);
}
}
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("linc");
User user = (User) propertyEditor.getValue();
System.out.println(user);
如何向Spring中注册PropertyEditor
/**
* 类型转化
*/
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
// 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
configurer.setCustomEditors(propertyEditorMap);
return configurer;
}
假设现在有一个Bean
@Component
public class UserService {
@Value("linc")
private User user;
public void test() {
System.out.println(user);
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService bean = context.getBean(UserService.class);
bean.test();
ConversionService
Spring中提供的类型转化服务,它比PropertyEditor更强大
public class StringToUserConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, User.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
User user = new User();
user.setName(String.valueOf(source));
return user;
}
}
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User user = conversionService.convert("linc", User.class);
System.out.println(user);
如何向Spring中注册ConversionService
/**
* ConversionService类型转化
*/
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
return conversionServiceFactoryBean;
}
TypeConverter
整合了PropertyEditor和ConversionService的功能是Spring内部用的
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor()
User user = typeConverter.convertIfNecessary("linc", User.class);
System.out.println(user);
OrderComparator
OrderComparator是Spring所提供的一种比较器,可以用来根据@Order注解或实现Ordered接口来执行值进行比较,从而可以进行排序
@ToString
public class A implements Ordered {
@Override
public int getOrder() {
return 1;
}
}
@ToString
public class B implements Ordered {
@Override
public int getOrder() {
return 2;
}
}
A a = new A();
B b = new B();
OrderComparator comparator = new OrderComparator();
System.out.println(comparator.compare(a, b));
List<Object> list = new ArrayList<>();
list.add(a);
list.add(b);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // [B(), A()]
另外,Spring中还提供了一个OrderComparator的子类AnnotationAwareOrderComparator,它支持用@Order来指定order值
@Order(3)
@ToString()
public class C {
}
@Order(1)
@ToString()
public class D {
}
C c = new C();
D d = new D();
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
System.out.println(comparator.compare(c,d));
List<Object> list = new ArrayList<>();
list.add(c);
list.add(d);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // [D(), C()]
BeanPostProcessor
BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,可以处理初始化前或者初始化后的逻辑
@Component
public class MyBeanPostProcessor 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;
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService bean = context.getBean(UserService.class);
bean.test();
一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean或某部分Bean)
我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程.
BeanFactoryPostProcessor
BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程
@Component
public class MyBeanFactoryBeanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("加工beanFactory");
}
}
FactoryBean
我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,我们可以使用FactoryBean
@Component
public class MyFactoryBean implements FactoryBean<UserService> {
@Override
public UserService getObject() throws Exception {
return new UserService();
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
我们自己创造了一个UserService,并且它将要成为Bean.但是通过这种方式创造出来的UserService的Bean,只会经历初始化后的逻辑,其他Spring的生命周期的步骤是不会经过的,比如说依赖注入.
通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?
@Bean定义的Bean是会经过完整的Bean生命周期的,而FactoryBean创建的对象只会经历初始化后的逻辑.
ExcludeFilter和IncludeFilter
这两个Filter是Spring扫描过程中用来过滤的,ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器. 比如我们不想让UserService成为Bean
@ComponentScan(value = "linc.cool",
excludeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class
)}
)
在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下Spring扫描过程中会认为类上有@Component注解的就是Bean
@ComponentScan(value = "linc.cool",
includeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class
)}
)
FilterType分为:
- ANNOTATION:表示是否包含某个注解
- ASSIGNABLE_TYPE:表示是否是某个类
- ASPECTJ:表示否是符合某个Aspectj表达式
- REGEX:表示是否符合某个正则表达式
- CUSTOM:自定义
MetadataReader、ClassMetadata、AnnotationMetadata
在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,比如类名、类中的方法、类上的注解这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类.
MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader.
SimpleMetadataReader去解析类时,使用的ASM技术.SimpleMetadataReaderFactory factory = new SimpleMetadataReaderFactory(); // 构造一个MetadataReader MetadataReader metadataReader = factory.getMetadataReader("linc.cool.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); }
为什么要使用ASM技术? Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术