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