BeanDefinition
A BeanDefinition represents the definition of a Bean, and there are many properties in a BeanDefinition that describe the characteristics of the Bean. Such as:
- Class, which represents the type of bean
- Scope, which represents the scope of the bean, singleton (singleton) or prototype (prototype)
- LazyInit, indicating whether the bean is lazily loaded
- InitMethodName, which represents the method to be executed for initialization of the bean
- DestoryMethodName, which indicates that the bean’s methods need to be executed when the bean is destroyed
- and more …
In Spring, we can define beans in one of the following ways: (1) XML; (2) annotation; (3) @bean, @Component (@Service, @Controller, @repository), which we call the ** declarative definition Bean**
We can also programmatically define beans directly through BeanDefinition, such as:
/ / define BeanDefinition
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
/ / set the scope
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
// Set the bean type
beanDefinition.setBeanClass(BeanTest.class);
// Set lazy loading
beanDefinition.setLazyInit(true);
/ / registered bean
applicationContext.registerBeanDefinition("test", beanDefinition);
Copy the code
Similar to declarative and programmatic transactions, beans defined by declarations such as, @bean, @Component, etc., will eventually be parsed by Spring into the corresponding BeanDefinition object and put into the Spring container.
BeanDefinitionReader
Beandefinitionreaders are BeanDefinitionreaders provided in the Spring container. These BeandefinitionReaders are less commonly used when we open with Spring, But the Spring source code is mostly used as an internal Spring infrastructure.
AnnotationBeanDefinitionReader
You can convert a class directly to a BeanDefinition and parse annotations on the class, for example:
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AnnotatedBeanDefinitionReaderTest.class);
AnnotatedBeanDefinitionReader annotationBeanDefinitionReader =
new AnnotatedBeanDefinitionReader(applicationContext);
annotationBeanDefinitionReader.register(UserService.class);
System.out.println(applicationContext.getBean(UserService.class));
Copy the code
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));
Copy the code
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner is scanner, but its role and BeanDefinitionReader similar, it can scan, scan a package path, class of scan to parse, such as, If the @Component annotation exists on the scanned class, the class will be resolved to a BeanDefinition, such as:
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ClassPathBeanDefinitionScannerTest.class);
ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner =
new ClassPathBeanDefinitionScanner(applicationContext);
classPathBeanDefinitionScanner.scan("com.summer.test.service");
System.out.println(applicationContext.getBean(UserService.class));
Copy the code
BeanFactory
BeanFactory stands for Bean factory, so it’s obvious that BeanFactory is responsible for creating beans and providing an API to get them. SpringApplicationContext is a subclass of BeanFactory and is defined in Spring’s source code as follows:
public interface ApplicationContext extends EnvironmentCapable.ListableBeanFactory.HierarchicalBeanFactory.MessageSource.ApplicationEventPublisher.ResourcePatternResolver {
// ...
}
Copy the code
First, in Java, interfaces can be ** multiple hierarchies, **ApplicationContext inherits both ListableBeanFactory and HierarchicalBeanFactory, And both ListableBeanFactory and HierarchicalBeanFactory inherit from BeanFactory, so we can assume that ApplicationContext inherits from BeanFactory, Just as Apple inherited fruit and BMW inherited cars, ApplicationContext is a kind of BeanFactory. It uses all the functions supported by BeanFactory. However, ApplicationContext is more powerful than BeanFactory. ApplicationContext also implements other basic interfaces. Such as MessageSource said internationalization, ApplicationEventPublisher said event publishing, EnvironmentCapable said access to environment variables, and so on, a detailed discussion about the ApplicationContext behind.
In the Spring implementation, when we new an ApplicationContext, the underlying BeanFactory is created, which is equivalent to using some of the ApplicationContext’s methods. Such as getBean(), the getBean of the underlying call to the BeanFactory.
In Spring the source code, the realization of the BeanFactory interface is a very important categories: DefaultLIsttableBeanFactory, is also very core.
So, we can use DefaultLIsttableBeanFactory directly, without the use of ApplicationContext an implementation class:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
System.out.println(beanFactory.getBean("userService"));
Copy the code
DefaultLIsttableBeanFactory is very strong, we can monitor the inheritance of it:From the perspective of inheritance relationship, it implements many interfaces and has the following functions: 1. AliasRegistry: supports alias function, a name can correspond to multiple aliases. 2, BeanDefinitionRegistry: You can register, save, remove, and retrieve a BeanDefinition. It is a ray that implements all the definitions in the AliasRegistry interface and supports aliasing. 5. ListableBeanFactory: This is a ray that implements all the definitions in the AliasRegistry interface.
ApplicationContext
AnnotationConfigApplicationContext
ClassPathXmlApplicationContext
internationalization
Define a MessageSource:
@Bean
public MessageSource messageSource(a) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
Copy the code
Once the Bean is created, we can use the MessageSource Bean object wherever we need to use internationalization. Also, since ApplicationContext also has internationalization capabilities, you can use it like this:
context.getMessage("test".null.new Locale("en"));
Copy the code
Resource to load
ApplicationContext also has resource loading capabilities. For example, you can use ApplicationConext to retrieve the contents of a file directly:
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("file://C:\\a.txt")
System.out.println(resource.contextLength())
Copy the code
Using ApplicationConext to do this will make your development more efficient. For example, we can also use:
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());
Copy the code
We can also get multiple resources
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("classpath:spring-context.xml")
System.out.println(resource.contextLength())
Copy the code
Gets runtime environment variables
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);
Copy the code
You can also parse files
@PropertySource("classpath:spring.properties")
Copy the code
To add a properties file to our environment variable, use the following code:
String abc = context.getEnvironment().getProperty("abc"."1");
System.out.println(abc);
Copy the code
Event publishing
Define events
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source); }}Copy the code
Define event listeners
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println("Received an event ,,,,,"); }}Copy the code
The caller
@Configuration
public class ApplicationEventTest {
@Bean
public ApplicationListener applicationListener(a) {
return new TestListener();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationEventTest.class);
context.publishEvent(new TestEvent(newObject())); }}Copy the code
Type conversion
Inside Spring, there are many places where you might want to convert a String to another type. Today we’ll look at the use of PropertyEditor, ConversionService, and TypeConverter.
PropertyEditor
PropertyEditor is a type converter provided by the JDK that first creates a bean:
@Service
public class OrderService {
@Value("orderVal")
private Order order;
public void test(a) {
System.out.println("The test order."+ order); }}Copy the code
Create a type converter to convert a string to an Order instance object.
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); }}Copy the code
Register converter and test code:
@Import({OrderService.class})
@Configuration
public class PropertyEditorTest {
@Bean
public CustomEditorConfigurer customEditorConfigurer(a) { 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) {
// Use mode 1
String2ObjectPropertyEditor propertyEditor = new String2ObjectPropertyEditor();
propertyEditor.setAsText("1");
Object value = propertyEditor.getValue();
System.out.println(value);
// Use mode 2
ApplicationContext applicationContext = newAnnotationConfigApplicationContext(PropertyEditorTest.class); OrderService orderItemService = applicationContext.getBean(OrderService.class); orderItemService.test(); }}Copy the code
ConversionService
ConversionService is a type converter provided in Sprign that is more powerful than PrppertyEditor. Define converter:
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(a) {
return Collections.singleton(new ConvertiblePair(String.class, Order.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return new Order("haha".32); }}Copy the code
Used alone
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2ObjectConversionService());
Order order = conversionService.convert("1", Order.class);
System.out.println(order);
Copy the code
Use in Spring:
@Bean
public ConversionServiceFactoryBean conversionService(a) {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new String2ObjectConversionService()));
return conversionServiceFactoryBean;
}
Copy the code
The Bean injection and invocation code:
// Test and inject
@Service
public class OrderService {
// Inject via @value
@Value("orderVal")
private Order order;
public void test(a) {
System.out.println("The test order."+ order); }}// Call code
ApplicationContext appliciton = new AnnotationConfigApplicationContext(ConvertTest.class);
OrderItemService orderItemService = appliciton.getBean(OrderItemService.class);
orderItemService.test();
Copy the code
TypeConverter
TypeConverter incorporates PropertyEditor and ConversionService to be used within Spring:
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(Order.class, new String2ObjectPropertyEditor());
Order order = typeConverter.convertIfNecessary("orderVal", Order.class);
System.out.println(order);
Copy the code
For example, AbstractBeanFacotry#adaptBeanInstance also works:
// AbstractBeanFacotry.java
<T> T adaptBeanInstance(String name, Object bean, @NullableClass<? > requiredType) {
// Check if required type matches the type of the actual bean instance.
// If the conversion type is not empty and the bean type does not match the target type
if(requiredType ! =null && !requiredType.isInstance(bean)) {
try {
// Try conversion
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 newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}return (T) bean;
}
Copy the code
OrderComparator
The OrderComparator is a comparator provided by Spring that can be Ordered by comparing according to the @Order annotation or implementing the Ordered interface. Such as:
public class A implements Ordered {
@Override
public int getOrder(a) {
return 1; }}Copy the code
public class B implements Ordered {
@Override
public int getOrder(a) {
return 2; }}Copy the code
Sort using:
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}}Copy the code
In addition, Spring also provides a OrderComparator subclasses: * * AnnotationAwareOrderComparator, * * it supports @ Order to specify the value of the Order, such as:
@Order(1)
public class A1 {}Copy the code
@Order(1)
public class B1 {}Copy the code
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}}Copy the code
BeanPostProessor
BeanPostProessor represents the bean’s post-processor. We can define one or more BeanPostProcessors, for example:
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");
}
returnbean; }}Copy the code
A BeanPostProcessor can do some additional user custom logic before and after the initialization of any Bean.
BeanFactoryPostProcessor
BeanFactoryPostProcessor represents the Bean factory’s post-processor, which is similar to BeanPostProcessor, which interferes with the Bean creation process. BeanFactoryPostProcessor is an interference in the creation process of BeanFactory. We can define a BeanFactoryProcessor as follows:
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("bean factory post processor"); }}Copy the code
We can extend BeanFacorty in the postProcessBeanFactory() method.
FactoryBean
As mentioned above, we can interfere with Spring’s Bean creation process through BeanPostProcessor, but if we want to create a Bean entirely by ourselves, we can, for example, implement it through FactoryBean.
@Component
public class TestFactoryBean implements FactoryBean {
@Override
public Object getObject(a) throws Exception {
UserService userService = new UserService();
return userService;
}
@Override
publicClass<? > getObjectType() {returnUserService.class; }}Copy the code
With the above code, we can create a UserService object and define it as a Bean, but beans defined in this way will only go through initialization and not through any other Spring lifecycle, such as dependency injection.
An @bean can also generate an object as a Bean, so what distinguishes it from a FactoryBean? In fact, in many scenarios, the two can be interchangeable, but in principle, the difference is obvious, @Bean Bean will go through the full Bean life cycle.
ExcludeFilter and IncluderFilter
These two filters are used for filtering during Spring scanning, ExcludeFilter means excluding Filter, and IncluderFilter means including Filter. For example, this means scanning all classes returned from the com. package, but excluding the UserService class, even if all @Component annotations on it do not become beans.
@ComponentScan(value = "com.summer.test.service", excludeFilters = { @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class) })
public class AppConfig {}Copy the code
For example, if the UserService class does not have an @Component annotation, it will be scanned as a Bean
@ComponentScan(value = "com.summer.test.service", includeFilters = { @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class) })
public class AppConfig {}Copy the code
FilterType is divided into:
- ANNOTATION.
- ASSIGNABLE_TYPE.
- ASPECTJ.
- REGEX.
- CUSTOM
MetadataReader/ClassMetaData/AnnotationMetadata
- MetadataReader metadata read
- ClassMetaData Metadata information of the class
- AnnotationMetadata Metadata metadata information for annotations
The test code
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
/ / MetadataReader construction
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader("com.summer.test.service.UserService");
// Get a ClassMetadata and get the class name
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// Gets an AnnotationMetadata, and gets annotation information on the class
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);
}
Copy the code
The resources
- spring.io