1,BeanDefinition
BeanDefinition represents a Bean definition. There are many attributes in BeanDefinition to describe the characteristics of a Bean. For example:
- class: indicates the Bean type
- Scope: indicates the Bean scope, singleton or prototype
- lazyInit: indicates whether the Bean is lazy loaded
- initMethodName: indicates the method to be executed during Bean initialization
- destroyMethodName: indicates the method to be executed when the Bean is destroyed
- Wait...
The declarative way to define beans is often used in Spring:, @ Bean, @ Component(@Service, @ Controller)
Of course, you can also define beans in an editorial way, that is, directly through BeanDefiniton, such as:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(User.class); beanDefinition.setScope("prototype"); // Set scope beanDefinition.setInitMethodName("init"); // Set initialization method beanDefinition.setLazyInit(true); // Set lazy load context.registerBeanDefinition("user",beanDefinition); System.out.println(context.getBean("user"));
Bean s defined by declarative transactions and editorial transactions will be resolved into corresponding BeanDefinition objects by Spring and put into the Spring container.
2. BeanDefinitionReader (BeanDefinitionReader)
AnnotatedBeanDefinitionReader
A class can be directly converted to BeanDefinition, and the annotations on the class will be parsed
The annotations it can parse are: @ Conditional, @ Scope, @ Lazy, @ Primary, @ DependsOn, @ Role, @ Description
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context); //Resolve User.class to BeanDefinition annotatedBeanDefinitionReader.register(User.class); System.out.println(context.getBean("user"));
XmlBeanDefinitionReader
It can parse tags
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 is a scanner, but its function is similar to BeanDefinitionReader. It can scan, scan a package path, and parse the scanned class. If there is @ Component annotation on the scanned class, the class will be parsed as a BeanDefinition.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.scan("com.example"); System.out.println(context.getBean("user"));
3,BeanFactory
BeanFactory represents a Bean factory, which is responsible for creating beans and providing API s for obtaining beans.
ApplicationContext is a kind of BeanFactory. It is defined in the Spring source code as follows:
ApplicationContext inherits listablebeanfactory and hierarchalbeanfactory, and listablebeanfactory and hierarchalbeanfactory inherit from BeanFactory. Therefore, we can think that ApplicationContext inherits BeanFactory and has all the functions supported by BeanFactory. It also has other functions, such as MessageSource for internationalization, ApplicationEventPublisher for event publishing, EnvironmentCapable for obtaining environment variables, and so on.
In the Spring source code, when we create a new ApplicationContext, the bottom layer will create a new BeanFactory. When using some methods in the ApplicationContext, such as getBean(), the bottom layer calls the getBean method of BeanFactory.
A very important implementation class of the BeanFactory interface is DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(User.class); beanFactory.registerBeanDefinition("user",beanDefinition); System.out.println(beanFactory.getBean("user"));
Class inheritance implementation structure of DefaultListableBeanFactory
DefaultListableBeanFactory has many functions:
- Alias registry: supports alias function. A name can correspond to multiple aliases
- BeanDefinitionRegistry: you can register, save, remove, and obtain a BeanDefinition
- BeanFactory: bean factory, which can obtain a bean object according to the name, type, or alias of a bean
- Singletonbean registry: you can directly register and obtain a singleton Bean
- Simpleliasregistry: it is a class that implements the functions defined in the alias registry interface and supports alias functions
- ListableBeanFactory: on the basis of BeanFactory, other functions are added to obtain the beanNames of all beandefinitions, the corresponding beanNames according to a type, and the mapping relationship of {type: corresponding Bean} according to a type
- Hierarchical BeanFactory: on the basis of BeanFactory, the function of obtaining parent BeanFactory is added
- DefaultSingletonBeanRegistry: it is a class that implements the SingletonBeanRegistry interface and has the function of directly registering and obtaining a singleton Bean
- ConfigurableBeanFactory: on the basis of hierarchical BeanFactory and SingletonBeanRegistry, it adds settings for parent BeanFactory, class loader (indicating that a class loader can be specified for class loading), Spring EL expression parser (indicating that the BeanFactory can parse EL expression), and type conversion service (indicates that the BeanFactory can be type converted), BeanPostProcessor can be added (indicates that the BeanFactory supports the post processor of a Bean), BeanDefinition can be merged, a Bean can be destroyed, and so on
- FactoryBean registrysupport: supports the functions of FactoryBean
- . AutowireCapableBeanFactory: it directly inherits BeanFactory. Based on BeanFactory, it supports automatic assembly of beans during the process of creating beans
- AbstractBeanFactory: it implements the ConfigurableBeanFactory interface and inherits the FactoryBeanRegistrySupport. This BeanFactory has comprehensive functions, but it cannot automatically assemble and obtain beanNames
- ConfigurableListableBeanFactory: inherits ListableBeanFactory, AutowireCapableBeanFactory and ConfigurableBeanFactory
- AbstractAutowireCapableBeanFactory: inherits AbstractBeanFactory, implements AutowireCapableBeanFactory and has the function of automatic assembly
- DefaultListableBeanFactory: it inherits AbstractAutowireCapableBeanFactory and implements the ConfigurableListableBeanFactory interface and BeanDefinitionRegistry interface. Therefore, DefaultListableBeanFactory has powerful functions
4,ApplicationContext
- Hierarchical BeanFactory: it has the function of obtaining the parent BeanFactory
- ListableBeanFactory: it has the function of obtaining beanNames
- Resourcepattern resolver: a resource loader that can obtain multiple resources (file resources, etc.) at one time
- EnvironmentCapable: you can get the runtime environment (the runtime environment function is not set)
- ApplicationEventPublisher: has the function of broadcasting events (without the function of adding event listeners)
- MessageSource: with internationalization function
ApplicationContext two important implementation classes: AnnotationConfigApplicationContext and ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
ClassPathXmlApplicationContext
internationalization
ApplicationContext has the function of internationalization
@Bean public MessageSource messageSource(){ ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("message"); return messageSource; }
With this Bean, you can use the MessageSource wherever you want to internationalize. At the same time, because ApplicationContext also has the function of nationalization, you can use it directly
context.getMessage("test", null, new Locale("en_CN")
Resource loading
ApplicationContext also has the function of resource loading. You can directly use ApplicationContext to obtain the content of a file
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Resource resource = context.getResource("file://D:\\testaa001.txt"); 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:com/example/spring/Test.class"); System.out.println(resource2.contentLength()); System.out.println(resource2.getURL()); Resource[] resources = context.getResources("classpath:com/example/spring/*.class"); for (Resource resource3 : resources) { System.out.println(resource3.contentLength()); System.out.println(resource3.getFilename()); }
Operation results:
Get runtime environment
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); 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); 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("spring"));
You can add parameters in a properties file to the runtime environment through @ PropertySource("classpath:spring.properties").
Event release
Define an event listener
@Bean public ApplicationListener applicationListener(){ return new ApplicationListener() { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("An event was received"); } }; }
Then publish an event
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); context.publishEvent("aaa");
Type conversion
1. Type conversion tool provided in JDK: PropertyEditor
public class StringToUser extends PropertyEditorSupport implements PropertyEditor { @Override public void setAsText(String text) throws IllegalArgumentException { User user = new User(); user.setName(text); this.setValue(user); } }
StringToUser stringToUser = new StringToUser(); stringToUser.setAsText("Xiao Ming"); User user = (User) stringToUser.getValue(); System.out.println(user);
Register the propertyEditor with Spring
@Bean public CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer(); Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>(); // Indicates that the StringToUserPropertyEditor can convert a String into a User type. In the Spring source code, if the current //If the object is String and the required type is User, the PropertyEditor will be used for type conversion propertyEditorMap.put(User.class, StringToUser.class); customEditorConfigurer.setCustomEditors(propertyEditorMap); return customEditorConfigurer; }
Suppose you have the following Bean
@Component public class UserService { @Value("Small ming") private User user; public void test(){ System.out.println(user.getName()); } }
2. The type conversion service ConversionService provided in Spring is more powerful than the property editor
Write a class to implement ConditionalGenericConverter and override the methods in it
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) source); return user; } }
DefaultConversionService conversionService = new DefaultConversionService(); conversionService.addConverter(new StringToUserConverter()); User user = conversionService.convert("Xiao Ming",User.class); System.out.println(user.getName());
Register ConversionService with Spring
@Bean public ConversionServiceFactoryBean conversionService(){ ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean(); conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter())); return conversionServiceFactoryBean; }
3. TypeConverter integrates the functions of PropertyEditor and ConversionService and is used internally in Spring
SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.registerCustomEditor(User.class,new StringToUser()); User user = typeConverter.convertIfNecessary("Xiao Mingming",User.class); System.out.println(user.getName());
OrderComparator
OrderComparator is a comparator provided by Spring. It can be used to compare values according to the @ Order annotation or implement the Ordered interface, so as to sort.
public class A implements Ordered { @Override public int getOrder() { return 3; } @Override public String toString() { return this.getClass().getSimpleName(); } }
public class B implements Ordered { @Override public int getOrder() { return 2; } @Override public String toString() { return this.getClass().getSimpleName(); } }
A a = new A(); B b = new B(); OrderComparator comparator = new OrderComparator(); System.out.println(comparator.compare(a,b)); List list = new ArrayList<>(); list.add(a); list.add(b); list.sort(comparator); System.out.println(list);
Spring also provides a subclass of OrderComparator: annotationawarerodecomparator, which supports @ order to specify the order value.
@Order(3) public class A { @Override public String toString() { return this.getClass().getSimpleName(); } }
@Order(2) public class B{ @Override public String toString() { return this.getClass().getSimpleName(); } }
A a = new A(); B b = new B(); AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator(); System.out.println(comparator.compare(a,b)); List list = new ArrayList<>(); list.add(a); list.add(b); list.sort(comparator); System.out.println(list);
5,BeanPostProcessor
BeanPostProcess represents Bena's post processor. We can define one or more beanpostprocessors
@Component public class WlBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if("userService".equals(beanName)){ System.out.println("Before initialization"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if("userService".equals(beanName)){ System.out.println("After initialization"); } return bean; } }
A BeanPostProcessor can make additional user-defined logic before and after the initialization of any Bean. We can judge the beanName for targeted processing (for a Bean or a department Bean). We can interfere with the process of Spring creating beans by defining BeanPostProcessor.
6,BeanFactoryPostProcessor
Beanfactoryprocessor represents the post processor of a Bean factory, which is actually similar to BeanPostProcessor.
BeanPostProcessor is the creation process of interference Bean, and beanfactorypost processor is the creation process of interference BeanFactory.
@Component public class WlBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("machining beanFactory"); } }
7,FactoryBean
Through FactoryBean, we can create a Bean ourselves
@Component public class WlFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { UserService userService = new UserService(); return userService; } @Override public Class<?> getObjectType() { return UserService.class; } }
Through the above code, we create a UserService object, which is also a Bean. However, the Bean of UserService created in this way will only be initialized, and other Spring life cycle steps will not go through, such as dependency injection. The difference between the object generated by @ Bean and the Bean is that the Bean defined by @ Bean will go through the complete Bean life cycle.
8. ExcludeFilter and IncludeFilter
These two filters are used for filtering during Spring scanning. ExcludeFilter means exclude Filter and IncludeFilter means include Filter
The following configuration means that the UserService class is excluded when scanning all classes under the com.example package. Even if it is annotated with @ Component, it will not become a Bean
@ComponentScan(value = "com.example", excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)}) @Configuration public class AppConfig { }
The following configuration will be scanned into a Bean even if there is no @ Component annotation on the UserService class
@ComponentScan(value = "com.example", includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)}) @Configuration public class AppConfig { }
FilterType is divided into:
- ANNOTATION: indicates whether an ANNOTATION is included
- ASSIGNABLE_TYPE: indicates whether it is a class
- AspectJ: indicates whether it conforms to an AspectJ expression
- REGEX: indicates whether it conforms to a regular expression
- CUSTOM: CUSTOM
In Spring's scanning logic, an AnnotationTypeFilter will be added to includeFilters by default, which means that by default, beans with @ Component annotation on the class will be considered during Spring scanning.
9,MetadataReader,ClassMetadata, AnnotationMetadata
In Spring, you need to parse class information, such as class name, methods in class and annotations on class. These can be called class metadata. Therefore, Spring abstracts class metadata and provides some tool classes.
MetadataReader represents the metadata reader of the class. The default implementation class is SimpleMetadataReader. ASM technology used by SimpleMetadataReader to parse classes.
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory(); //Construct a MetadataReader MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.example.spring.UserService"); //Get a ClassMetadata and get the class name ClassMetadata classMetadata = metadataReader.getClassMetadata(); System.out.println(classMetadata.getClassName()); //Get an AnnotationMetadata and get the annotation information on the class AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); for (String annotationType : annotationMetadata.getAnnotationTypes()) { System.out.println(annotationType); }