BeanDefinition
Definition of Bean. In Spring, how can we define a Bean?
- @Bean
- @Component(@Service,@Controller)
Also, you can use BeanDefinition
For example, we can define a Bean by defining a BeanDefinition object:
// A BeanDefinition is defined AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); // The type of the current Bean object beanDefinition.setBeanClass(User.class); // Register BeanDefinition in BeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerBeanDefinition("user", beanDefinition); // Get Bean System.out.println(beanFactory.getBean("user"));
We can also set other properties of a Bean through BeanDefinition
beanDefinition.setScope("prototype"); // Set scope beanDefinition.setInitMethodName("init"); // Set initialization method beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); // Set up auto assembly model
wait
In short, beans defined by @ Bean, @ Component and other methods will eventually be resolved into BeanDefinition objects.
BeanDefinition can be understood as a concept at the underlying source level, or as a way of using an API provided by Spring.
BeanDefinitionReader
BeanDefinitionReader is divided into several categories:
AnnotatedBeanDefinitionReader
A class can be directly converted to BeanDefinition, and the annotations on the class will be parsed
Note: the annotations it can resolve are: @ Conditional, @ Scope, @ Lazy, @ Primary, @ DependsOn, @ Role, @ Description
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory); // Resolve User.class to BeanDefinition annotatedBeanDefinitionReader.register(User.class); System.out.println(beanFactory.getBean("user"));
XmlBeanDefinitionReader
Labels can be parsed
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml"); System.out.println(beanFactory.getBean("user"));
ClassPathBeanDefinitionScanner
This is not a BeanDefinitionReader, but its function is similar to that of BeanDefinitionReader. It can scan, scan a package path, and parse the scanned class. For example, if the @ Component annotation exists on the scanned class, the class will be parsed as a BeanDefinition
BeanFactory
In Spring, the core implementation class of BeanFactory is DefaultListableBeanFactory
It implements many interfaces, indicating that it 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
Through the above analysis, we can know that we can do many things through DefaultListableBeanFactory, such as:
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(User.class); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // Register BeanDefinition beanFactory.registerBeanDefinition("user", beanDefinition); // Register alias beanFactory.registerAlias("user", "user1"); // Register BeanPostProcessor beanFactory.addBeanPostProcessor(new LubanBeanPostProcessor()); // Get Bean object System.out.println(beanFactory.getBean("user1")); // Get beanNames by type System.out.println(beanFactory.getBeanNamesForType(User.class));
ApplicationContext
Firstly, ApplicationContext is an interface, which can be understood as a special BeanFactory
- 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
There are two more important implementation classes:
7. AnnotationConfigApplicationContext
8. ClassPathXmlApplicationContext
AnnotationConfigApplicationContext
- ConfigurableApplicationContext: inherits the ApplicationContext interface and adds functions such as adding event listener, adding beanfactoryprocessor, setting Environment, and obtaining ConfigurableListableBeanFactory
- AbstractApplicationContext: implements the ConfigurableApplicationContext interface
- GenericApplicationContext: inherits AbstractApplicationContext, implements the BeanDefinitionRegistry interface, has all the functions of ApplicationContext, and can register BeanDefinition. Note that this class has an attribute (DefaultListableBeanFactory beanFactory)
- AnnotationConfigRegistry: you can register a class as BeanDefinition separately (you can handle the @ Configuration annotation on this class, and you can already handle the @ Bean annotation), and scan it at the same time
- AnnotationConfigApplicationContext: inherits GenericApplicationContext, implements the annotationconfigaregistry interface, and has all the above functions
ClassPathXmlApplicationContext
It also inherits AbstractApplicationContext, but compared with AnnotationConfigApplicationContext, its function is not as powerful as AnnotationConfigApplicationContext. For example, BeanDefinition cannot be registered
internationalization
First define a MessageSource:
@Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; }
With this Bean, you can use the MessageSource anywhere you want to internationalize.
At the same time, because ApplicationContext also has the function of nationalization, it can be used directly as follows:
annotationConfigApplicationContext.getMessage("test", null, new Locale("en_CN"))
Resource loading
ApplicationContext also has the function of resource loading. For example, you can directly use ApplicationContext to obtain the content of a file:
Resource resource = annotationConfigApplicationContext.getResource("file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java"); System.out.println(resource.contentLength());
You can think about it. If you do not use ApplicationContext, but implement this function yourself, it will take more time.
For example, you can:
Resource resource = annotationConfigApplicationContext.getResource("classpath:com/luban/entity/User.class"); System.out.println(resource.contentLength());
You can also get multiple at once:
Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/luban/service/*.class"); for (Resource resource : resources) { System.out.println(resource.contentLength()); }
This function uses the policy mode.
Get runtime environment
// Gets the environment of the operating system allowed by the JVM annotationConfigApplicationContext.getEnvironment().getSystemEnvironment(); // Get some properties of the JVM itself, including those set by - D annotationConfigApplicationContext.getEnvironment().getSystemProperties(); // You can also directly obtain the properties in an environment or properties file annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")
Note that you can use
@PropertySource("classpath:application.properties")
To add parameters in a properties file to the runtime environment
Event release
Define an event listener first
@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.publishEvent("kkk");
Type conversion
PropertyEditor
Type conversion tool classes provided in 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("1"); User value = (User) propertyEditor.getValue(); System.out.println(value);
How to register a PropertyEditor with Spring:
@Bean public CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer(); Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>(); propertyEditorMap.put(User.class, StringToUserPropertyEditor.class); customEditorConfigurer.setCustomEditors(propertyEditorMap); return customEditorConfigurer; }
Suppose there are the following beans:
@Component public class UserService { @Value("true") User test; public void test() { System.out.println(test); } }
Then the test attribute can normally complete the attribute assignment
ConversionService
The type transformation service provided in Spring is more powerful than the property editor
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 value = conversionService.convert("1", User.class); System.out.println(value);
How to register ConversionService with Spring:
@Bean public ConversionServiceFactoryBean conversionService() { ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean(); conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter())); return conversionServiceFactoryBean; }
TypeConverter
It integrates the functions of PropertyEditor and ConversionService and is used internally in Spring
SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor()); //typeConverter.setConversionService(conversionService); User value = typeConverter.convertIfNecessary("1", User.class); System.out.println(value);
BeanPostProcessor
The post processor of a Bean can interfere in the process of creating each Bean. It is an attribute in BeanFactory, which is described in detail in the life cycle of a Bean.
BeanFactoryPostProcessor
The post processor of the Bean factory belongs to an attribute in the ApplicationContext. After the ApplicationContext instantiates a BeanFactory, it can continue to process the BeanFactory using the BeanFactory postprocessor.
Programmers can indirectly set BeanFactory through BeanFactory postprocessor. For example, the CustomEditorConfigurer above is a BeanFactory postprocessor, through which we can add a custom PropertyEditor to BeanFactory.
FactoryBean
Allows programmers to customize an object and indirectly put it into the Spring container through FactoryBean to become a Bean.
So what's the difference between @ Bean and @ Bean? Because @ Bean can also customize an object to make it a Bean.
The difference is that using FactoryBean can be more powerful, because you can implement other interfaces in Spring by defining an XxFactoryBean class. For example, if you implement the BeanFactoryAware interface, you can obtain the Bean factory in your XxFactoryBean, so as to use the Bean factory to do more you want to do, but @ Bean can't.