The first step in source code analysis is to set a goal. Our goal is — how does Spring load objects via the @bean annotation? According to this goal we will naturally find AnnotationConfigApplicationContext.

AnnotationConfigApplicationContext

In order to better understand and become familiar with an object, we need to understand its inheritance relationship and the functions and features provided by the various interfaces it implements.

AnnotationConfigApplicationContext inheritance diagram is as follows:

Here we make a preliminary introduction on AnnotationConfigApplicatoinContext.

The topmost BeanFactory is Spring’s top-level interface to access the Bean container and the most basic client view of the Bean container. HierarchicalBeanFactory is a subinterface to BeanFactory, on top of which methods are defined to get the parent BeanFactory, giving implementation classes inheritance properties.

The ListableBeanFactory is also a subinterface of the BeanFactory as well as HierarchicalBeanFactory, It defines a set of interfaces to get Bean instances and information through enumerations (collections) and to get BeanDefinition information.

In addition to inheriting HierarchicalBeanFactory and ListableBeanFactory, the ApplicationContext Also inherited EnvironmentCapable, MessageSource, ApplicationEventPublisher, ResourcePatternResolver. ApplicationContext adds methods to get the ApplicationContext on top of the BeanFactory. Including EnvironmentCapable is loading Profiles feature sources, MessageSource is the source of parsing string information and internationalization features, ApplicationEventPublisher Yes Indicates the source of time rollback. ResourcePatternResolver indicates the source of resource path resolution.

ConfigurableApplicationContext besides inherits the ApplicationContext also inherited the Lifecycle and Closeable. ConfigurableApplicationContext on ApplicationContext defines a set of application context of setting method, one of the most important is the refresh () method, is used to reset and start the application context.

Finally AbstractApplicationContext and GenericApplicationContext is on the front so all of the features of a preliminary and general.

Tip: when you look at the source code, you must first look at class annotations and method annotations to avoid diving into the deep sea of source code.

BeanFactory

As mentioned earlier, the BeanFactory is the top-level interface to Spring’s access Bean container, which defines a set of interfaces for getting and judging Bean properties.

Here is its core set of methods:

  • GetBean (String) : Gets the bean instance by bean name.
  • GetBean (Class

    ) : Gets the bean instance from the bean type.
  • GetBeanProvider (Class < T >) : BeanProvider is a variant of ObjectFactory. Java 8’s Optional provides a richer way to get beans.
  • ContainsBean (String) : Determines whether it contains a BeanDefinition or an externally registered singleton by the Bean name.
  • IsSingleton (String) : Checks whether this bean is a singleton.
  • IsPrototype (String) : Checks whether this bean is a prototype pattern.
  • isTypeMatch(String, Class
    ) : determines whether the given Bean name and type match.
  • GetType (String) : Gets the type of the Bean name.
  • GetAliases (String) : Gets the group name corresponding to the Bean name.

Beautiful design idea: read-write separation

HierarchicalBeanFactory

HierarchicalBeanFactory is a subinterface of the BeanFactory, which defines two interfaces.

  • GetParentBeanFactory () : Gets the parent BeanFactory.
  • ContainsLocalBean (String) : Determines whether the local contains a Bean with the given Bean name.

Nice design idea: let the same object have inheritance relationship, that is, broaden the scope of the object and can closely link objects of the same type together

ApplicationContext

ApplicationContext is one of the most important objects in Spring. It defines a set of interfaces for getting ApplicationContext:

  • GetId () : obtains the application context ID.
  • GetApplicationName () : Gets the application name. Guesses can be assigned by Profiles.
  • GetDisplayName () : Gets a friendly context name.
  • GetStartupDate () : Gets the timestamp of the first startup of the current application.
  • GetParant () : Gets the parent ApplicationContext.
  • GetAutowireCapableBeanFactory () : get AutowireCapableBeanFactory object.

About AutowireCapableBeanFactory here, not ApplicationContext didn’t realize AutowireCapableBeanFactory, But it can be from its getAutowireCapableBeanFactory AutowireCapableBeanFactory () method. AutowireCapableBeanFactory more for some of the life cycle of Spring control classes, as other want to use Spring DI external framework provides a set of integrated methods. This interface is rarely used internally in Spring.

ConfigurableApplicationContext

This is the bottom interface of AnnotationConfigApplicationContext relationship chain. There are beginning to be different inheritance and implementation branches for Web and non-Web contexts.

  • SetId () : sets the application context ID.

  • SetParent (ApplicationContext) : Sets the parent ApplicationContext.

  • SetEnvironment (ConfigurableEnvironment) : Sets environment information. The environment information is obtained from profile files such as YAML, XML, and properties.

    SetApplicationStartup () : setApplicationStartup, which is the Spring class for performing non-functional operations on logging and logging.

  • AddBeanFactoryPostProcessor (spring BeanFactoryPostProcessor) : Add BeanFactoryPostProcessor, a callback interface used to change Bean properties in the BeanFactory lifecycle.

  • addApplicationListener(ApplicationListener<? >) : Adds listeners to pass context change events, such as update, close, and so on.

  • SetClassLoader (ClassLoader) : Class path resource or ClassLoader.

  • AddProtocolResolver (ProtocolResolver) : adds a ProtocolResolver to resolve different resource paths and names.

  • Refresh () : Refresh persistent configuration information, which destroys and recreates the bean instance (singleton) that has been created.

  • RegisterShutdownHook () : Registers a JVM runtime shutdown hook.

  • Close () : Closes ApplicationContext and frees all resources.

  • IsActive () : checks whether ApplicationContext isActive. If ApplicationContext calls refresh() at least once and does not call close(), it isActive.

  • GetBeanFactory () : obtain ConfigurableListableBeanFactory object.

AbstractApplicationContext

Provide ApplicationContext and most ConfigurableApplicationContext default implementation. It also inherits DefaultResourceLoader, which is a resource loader.

Some of the key is AbstractApplicationContext implements the refresh () method.

GenericApplicationContext

Further, all GenericApplicationContext provides ApplicationContext and ConfigurableApplicationContext, BeanDefinitionRegistry is implemented to complete the registration and retrieval of BeanDefinition.

AnnotationConfigApplicationContext

All AnnotationConfigApplicationContext inherited GenericApplicationContext, realize the AnnotationConfigRegistry at the same time. It also extends the ability to load a particular Annotation Bean by scanning the package or directly calling the registration method.

The basic case

A Package path is prepared and several simple test classes are placed under it.

ConfigurationForScan. Java:

@Configuration
public class ConfigurationForScan {
    @Bean
    public TestBean testBean(a) {
        return newTestBean(); }}Copy the code

ComponentForScan. Java:

@Component
public class ComponentForScan {}Copy the code

TestBean. Java:

public class TestBean {
    public String name = "Your Test Bean";
}
Copy the code

Test scan and fetch classes:

public class AnnotationApplicationContextTest {
    @Test
    public void scanAndRefresh(a) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        / / scan
      	ctx.scan("org.example.annotation");
        / / refresh
        ctx.refresh();
      
				/ / load @ Configuration
        final ConfigurationForScan configurationForScan = ctx.getBean(uncapitalize(ConfigurationForScan.class.getSimpleName()), ConfigurationForScan.class);
        Assertions.assertNotNull(configurationForScan);
        / / load @ Component
        final ComponentForScan componentForScan = ctx.getBean(uncapitalize(ComponentForScan.class.getSimpleName()), ComponentForScan.class);
        Assertions.assertNotNull(componentForScan);
        // Load the Bean defined by the @bean method in @Configuration
        final TestBean testBean = ctx.getBean("testBean", TestBean.class);
        Assertions.assertEquals("Your Test Bean", testBean.name);

      	/ / by
        final Map<String, Object> map = ctx.getBeansWithAnnotation(Configuration.class);
        if (map.containsKey("configDemo")) {
            final ConfigurationForScan configDemo = (ConfigurationForScan) map.get(uncapitalize(ConfigurationForScan.class.getSimpleName()));
            TestBean testBean2 = configDemo.testBean();
            Assertions.assertEquals("Your Test Bean", testBean2.name); }}}Copy the code

Scan () source is the AnnotationConfigRegistry AnnotationConfigApplicationContext realized it, Here AnnotationConfigApplicationContext itself is a registry of the Annotation configuration, can finish the registration and access to the Annotation configuration operation.

The basic function of Scan () is to scan the target package path and screen out the classes that meet the requirements. The class is abstracted as a BeanDefinition and registered in the container. At this time, no instance (singleton) of the class has been generated. Annotations that match a target are @Configuration, @Component, @named, etc. Where @named is the annotation of Jsr330. Spring is compatible with JSR330.

The source of the refresh () is and by AbstractApplicationContext ConfigurableApplicationContext achieve it. Refresh () implements a lot of things, which can be summarized as follows: Load environment parameters such as Profiles, life cycle methods before performing bean instantiation, instantiating beans (instantiating BeanDefinition), life cycle methods after performing bean instantiation, destroying and refreshing already created bean instances and environment configuration, and so on.

In addition to scanning, beans can be registered directly via Register (), which is also the interface defined by AnnotationConfigRegistry. Spring mostly registers its beans this way.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(ConfigurationForScan.class, ComponentForScan.class);
Copy the code

Tip: Reading the test cases that come with the source code is a great way to get to know and become familiar with objects.

AnnotationConfigWebApplicationContext

AnnotationConfigWebApplicationContext is a Web version of AnnotationConfigApplicationContext, here we overview the can.

AnnotationConfigApplicationContext inheritance diagram is as follows:

As we can see from the diagram AnnotationConfigWebApplicationContext with AnnotationConfigApplicationContext inheritance chain in ConfigurableApplicationContext has a branch here. That is to say AnnotationConfigWebApplicationContext actually has all the features of AnnotationConfigApplicationContext.

ConfigurableWebApplicationContext inherited WebApplicationContext. WebApplicationContext provides access to the ServletContext interface, ConfigurableWebApplicationContext ServletContext interface provides a set of Settings.

AbstractRefreshableWebApplicationContext inherited AbstractRefreshableConfigApplicationContext and implemented ConfigurableWebApplicationContext.

Fun fact: This is a good place to realize that Java inheritance is similar to biological classification, and that different implementation classes have a common ancestor and therefore share common features.

ConfigurableWebApplicationContext

On ConfigurableApplicationContext provides a set of method of setting up Web context. It is important to note that setters provided by the current interface need to be called before calling methods defined by other top-level interfaces; other top-level interfaces cannot generate the context themselves.

  • SetServletContext (ServletContext) : Sets the ServletContext.
  • SetServletConfig (ServletConfig) : Sets the ServletConfig.
  • SetNamespace (String) : Sets the namespace for the current Web Application Context. By default, the root Web Application Context has no namespace.
  • setConfigLocattions(String…) : Sets the configuration load path. If not, the namespace or top-level Web Application context configuration is used by default.

AnnotationConfigWebApplicationContext

AnnotationConfigWebApplicationContext inherited AbstractRefreshableWebApplicationContext and implements the AnnotationConfigRegistry interface. Like AnnotationConfigApplicationContext realized by scanning package or direct call registration method to load with a particular Annotation the function of the Bean.

The basic case

public class AnnotationApplicationContextTest {
		@Test
    public void configLocationWithBasePackage(a) {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.setConfigLocation("org.example.annotation");
        ctx.refresh();

        TestBean bean = ctx.getBean(TestBean.class);
        assertThat(bean).isNotNull();
    }

    @Test
    public void withBeanNameGenerator(a) {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.setBeanNameGenerator(new AnnotationBeanNameGenerator() {
            @Override
            public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
                return "custom-" + super.generateBeanName(definition, registry); }}); ctx.setConfigLocation(ConfigurationForScan.class.getName()); ctx.refresh(); assertThat(ctx.containsBean("custom-configurationForScan")).isTrue(); }}Copy the code

By AbstractRefreshableConfigApplicationContext setConfigLocation () implementation, for direct loading under the specific package path configuration class.

SetBeanNameGenerator () is to provide used to set the modified Bean name AnnotationApplicationContextTest callback methods.

conclusion

This article did not involve code temporarily details, on the premise of understanding AnnotationConfigApplicationContext and design ideas in the code details have twice the result with half the effort. Finally, Spring fully embodies the essence of abstraction and the ubiquitous idea of read-write separation. The use of Java inheritance and interfaces is a masterstroke.

Welcome to my personal blog menfre.info.