refresh method source code analysis

Posted by nielsg on Tue, 18 Jan 2022 16:35:59 +0100

Post processor

It is also a Bean that needs to be registered in the container

◆ the methods in it will be called by the container at a specific time
◆ the implementation extends the Bean without changing the container or the core logic of the Bean

◆ package the Bean, affect its behavior, modify the content of the Bean, etc

Type of PostProcessor

It is divided into container level postprocessors and Bean level postprocessors

◆BeanDefinitionRegistryPostProcessor
◆BeanFactoryPostProcessor

◆BeanPostProcessor

The first two are container level processors, and the last one is bean level processors.

BeanDefinitionRegistryPostProcessor: responsible for the registration of custom beandefinition. Allow more custom beandefinitions to be registered before normal beanfactoryprocessor detection starts

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

Inheriting beanfactoryprocessor can be regarded as a special beanfactoryprocessor. He has only one way.

Method: create an instance of BeanDefinition and register it in the formal parameter register

Write implementation classes. You must first inject its implementation class into the container before you can talk to the container

@Configuration
public class CustomizedBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
      Class<User> clazz = User.class;//Create class object
      //Tool for obtaining BeanDefinition
      BeanDefinitionBuilder builder=BeanDefinitionBuilder.genericBeanDefinition(clazz);
      GenericBeanDefinition definition= (GenericBeanDefinition) builder.getBeanDefinition();
      //Register BeanDefinition in registry
      registry.registerBeanDefinition("userhaha",definition);
   }

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

   }
}

Get the bean instance we just registered in the main function

Beanfactoryprocessor: affects the behavior of the container

BeanPostProcessor: for each bean instance created by the container, BeanPostProcessor will obtain callback execution from the container before calling container initialization and after any bean initialization callback. Note that it is not a BeanDefinition instance,

//Call before bean initialization
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   return bean;
}

@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

code implementation

@Configuration
public class CustomizedBeanPostProcessor implements BeanPostProcessor {

   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println(beanName + "Called postProcessBeforeInitialization");
      return bean;
   }

   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println(beanName+"Called postProcessAfterInitialization");
      return bean;
   }


}

When the main function is executed, it is found that each spring managed bean will execute the two methods, and execute before and after first

Summary:

We can use the capability of BeanPostProcessor to wrap the bean, that is, after the bean is created, wrap the bean with unified logic in postProcessAfterInitialization, such as time-consuming statistical logging, and then return the enhanced bean.

In the source code:

When the sorted postprocessors are executed one by one, the responsibility chain mode is adopted, and each receiver contains a reference to another receiver. If an object cannot process the request, the object is forwarded to the next recipient, and so on.

Aware

The container does not intrude into the logic of the bean itself, so the bean does not need to know the state of the container and can use the container directly. However, in some cases, if the container needs to be operated directly in the bean, then the perception of the container needs to be set in the bean, which is the function of Aware interface.

There are no methods in this interface, so it can only be used as a label.

Aware: perceptible.

ApplicationContextAware

public interface ApplicationContextAware extends Aware {

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

When the container creates the bean instance, pass the instance of the container itself as a parameter to the bean for use

BeanFactoryAware: get the current BeanFactory so that you can call the container's service.

ApplicationEventPublisherAware: get the events published by the publisher instance

Call the relevant interface if you want to realize any function

Get the name s of all beandefinition s registered in this container


@Controller
public class WelcomeController implements ApplicationContextAware, BeanNameAware {
   private String name;
   private ApplicationContext myContainer;

   @Autowired
   private WelcomeService welcomeService;

   public void handleRequest(){
      welcomeService.sayHello("come from controller Greetings from");
      System.out.println("Who am I?"+name);
      // Get the name s of all beandefinition s registered in this container
      String[] beanDefinitionNames = myContainer.getBeanDefinitionNames();
      for (String beanDefinitionName : beanDefinitionNames) {
         System.out.println("Summon a divine beast and obtain:"+beanDefinitionName);
      }

   }


   @Override
   public void setBeanName(String name) {
      this.name=name;
   }

   @Override
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.myContainer=applicationContext;
   }
}

main function

@Configuration
@ComponentScan("com.imooc")
public class Entrance {

   public static void main(String[] args) {
      //Get class
      AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);
      //Get bean object name
      String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
      for (String beanDefinitionName : beanDefinitionNames) {
         System.out.println(beanDefinitionName);//Print container managed bean s
      }

      //Get bean object
      WelcomeController welcomeController = (WelcomeController) applicationContext.getBean("welcomeController");
      welcomeController.handleRequest();//Call object method
      User user = (User) applicationContext.getBean("userhaha");
      System.out.println("CustomizedBeanDefinitionRegistryPostProcessor Objects created:"+user);
   }
}

be careful:

To obtain the resources provided by the container, in addition to inheriting the Aware interface, the class itself must be a bean managed by the spring container.

Event listening mode

Callback function

◆ register custom methods with components so that they can be called in specific scenarios

The Thread class is a component, and the run() method is a callback function. We don't want to directly call the run method in Runnable, but we want the Thread component to execute it at a certain time, which is after calling the start method.

package demo.pattern.callback;

public class CallbackDemo {
    public static void main(String[] args) {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I'm going to have a rest");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("I'm going to be recalled");
            }
        });

        thread.start();

    }
}

Event listener mode

The listener will listen for the event of interest and respond as soon as the event occurs

  • Event Source: for example, for a button, if you want to make a button respond to an event, you need a listener

  • Event Listener: it can be called only after registering with the event source. It is mainly used to listen to events and process or forward events.

  • Event Object: responsible for information transfer between event source and event listener

1. Create event

@Getter@Setter
public class Event {
    private String type;
}

2. Create event listener

public interface EventListener {
    public void processEvent(Event event);
}

Implementation class

public class SingleClickEventListener implements EventListener {
    @Override
    public void processEvent(Event event) {
        if("singleclick".equals(event.getType())){
            System.out.println("Click triggered");
        }
    }
}
public class DoubleClickEventListener implements EventListener {
    @Override
    public void processEvent(Event event) {
        if("doubleclick".equals(event.getType())){
            System.out.println("Double click triggered");
        }
    }
}

3. Create event source

Because you need to register event listeners in the event source, there are multiple event listeners, so you need to define a List collection. Provide a common method for external input data and output data, that is, the method of publishing events. It is mainly published to the listener. After traversing all listeners, an event is sent, and the listener processes the event

public class EventSource {
    private List<EventListener> listenerList=new ArrayList<>();
    
    public void register(EventListener listener){
        listenerList.add(listener);
    }
    
    public void publishEvent(Event event){
        for (EventListener listener : listenerList) {
            listener.processEvent(event);
        }
    }
}

You also need to register the lisener in the event source. After registration, the event source will publish the event and hand it over to the event listener for processing.

public class EventModeDemo {
    public static void main(String[] args) {
        Event event=new Event();
        EventSource eventSource=new EventSource();
        SingleClickEventListener singleClickEventListener=new SingleClickEventListener();
        DoubleClickEventListener doubleClickEventListener=new DoubleClickEventListener();
        eventSource.register(singleClickEventListener);//Register the listener with the event source
        event.setType("singleclick");//Set the properties of the event
        eventSource.publishEvent(event);//Publish event
    }
}

The event listener mode can be decoupled, and the event listener and time source can be developed separately. Only events are used as a link, not how the other party implements it. The event listener is actually an implementation of the observer mode. The event source component is similar to the event equal to the subject primary key of the observer. The event listener targets the observer in the observer mode.

Event driven model of Spring

Three components of event driven model

Event: applicationevent abstract class

public abstract class ApplicationEvent extends EventObject {

EventObject inherited from jdk. All events will inherit from ApplicatinEvent and obtain events through the source member variable inside. Event source is the place where events are published, which refers to the container itself.

ApplicationEvent does not only refer to container events. In order to customize events for containers, ApplicationContextEvent subclasses are generated to represent container events. The following are the implementation classes of the framework.

After publishing an event of any type in the container, it will be automatically marshaled into the PayloadApplicationEvent class.

public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

Event listener: ApplicationListener

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

   /**
    * Handle an application event.Handling events
    * @param event the event to respond to
    */
   void onApplicationEvent(E event);

}

Users can implement this interface, implement the methods inside, and implement custom listeners. You can also use annotations to listen to classes.

In this way, you can promote this class to a listener and listen with the sayHello method.

SmartApplicationListener

You can sort events by inheriting order

public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

Judge whether the event type and event source type match the current listener, so that the listener can filter the events or event sources of interest.

boolean supportsEventType(Class<? extends ApplicationEvent> eventType);

default boolean supportsSourceType(@Nullable Class<?> sourceType) {
		return true;
	}

GenericApplicationListener

public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

Resolvable type: a tool for obtaining generic information. It can obtain any information of generic, similar to reflection.

boolean supportsEventType(ResolvableType eventType);

default boolean supportsSourceType(@Nullable Class<?> sourceType) {
		return true;
	}

Event publishers: Publisher and multicast

You can obtain the ApplicationEvnetPublisher instance through Aware in the bean. In fact, you can obtain the container instance and publish custom events to the custom eventListener registered in the container for processing.

public interface ApplicationEventPublisherAware extends Aware {

The discovery container ApplicationContext inherits ApplicationEventPublisher

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
      MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

ApplicationEventPublisher

public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
		publishEvent((Object) event);
	}

    
    	void publishEvent(Object event);
}

Both of its methods are used to publish events, that is, this interface can only be used to publish events

ApplicationEventMulticaster

public interface ApplicationEventMulticaster {

It has the functions of adding and deleting listener s and publishing

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

   @Nullable
   private Executor taskExecutor;

Executor: executor, which indicates that it supports multithreading to process listeners.

Why do I need two interfaces, ApplicationEventPublisher and applicationeventmulticast?

Since ApplicationEventMulticaster already has all the functions, why not use it instead of ApplicationEventPublisher?

For example, the bean container itself (applicationcontext) only wants to publish events instead of maintaining event listeners, so spring further divides the event source, abstracts the event publisher interface, and uses applicationeventmulticast as a proxy, just as the applicationcontext uses our DefaultListableFactory as a proxy, Let ApplicationEventPublisher's implementation class

To implement the logic in publishEvent. The main implementation of ApplicationEventPublisher is to call the multicast event of the applicationeventmulticast implementation class to publish the time.

Refresh logic of Spring container by hand

Refresh means to clear the BeanFactory to its initial state, and then fill various bean instances according to the program intention

When registering the beanDefinition of the annotation, the DefaultListableBeanFactory instance has been created before registering the primary key class, that is, when calling the constructor of the container,

Postprocessor ApplicationContextAwareProcessor: when bean instances inherit the ApplicationContextAware interface, inject ApplicationContext objects into these bean instances.

registerBeanPostProcessors(beanFactory);

After calling the container level postprocessor, the next step is the bean level postprocessor. The register step is to register the bean level postprocessors previously defined into the container, so that when calling the getBean method to create bean instances, these postprocessors can be triggered to execute some specific logic in specific links, such as AOP weaving

initApplicationEventMulticaster();

Initialize event Publisher: used to receive different events sent by the ApplicationEventPublisher interface class and send them to different event listeners for processing.

onRefresh(): a hook method used to initialize other special beans, which is executed before the initialization of the singleton bean.

registerListeners();

Register relevant listeners with the previously initialized applicationeventmulticast to listen to different events

/**
 * Load or refresh a persistent configuration, which may be an XML file, a property file, or a relational database schema.
 * Since this is a startup method, if it fails, the created singleton should be destroyed to avoid dangling resources.
 * In other words, after the method is called, it is either fully instantiated or not instantiated at all.
 * @throws If the bean factory cannot be initialized, a BeansException exception is thrown
 * @throws If it has been initialized and does not support multiple flushes, an IllegalStateException is thrown
 */
@Override
public void refresh() throws BeansException, IllegalStateException {
   // Lock the container refresh to avoid initialization or destruction when the container is in the refresh stage
   synchronized (this.startupShutdownMonitor) {
      // Call the method that the container is ready to refresh, obtain the current time of the container, and set the synchronization ID for the container. The specific method is as follows:
      prepareRefresh();

      //Tell the subclass to start the refreshBeanFactory() method and load the Bean definition resource file from
      //The subclass's refreshBeanFactory() method starts, and there are abstract methods in it
      //For xml configuration, finally create an internal container, which is responsible for the creation and management of beans. This step will register the BeanDefinition
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Register some system beans required in the container For example, classloader, Bean factory, postprocessor, etc
      prepareBeanFactory(beanFactory);

      try {
         //Allow subclasses of containers to register postProcessor and hook methods
         postProcessBeanFactory(beanFactory);

         // Activate beanfactoryprocessors registered as beans in the container
         //For annotation containers, org springframework. context. annotation. ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
         //Method scans all beandefinitions in the application and registers them in the container
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register the BeanPostProcessor that intercepts the bean creation process
         registerBeanPostProcessors(beanFactory);

         // Find the Bean of "messageSource" and provide it to ApplicationContext for use,
         // Make ApplicationContext international.
         initMessageSource();

         // Initialize the applicationeventmulticast class as the event publisher,
         // All event listener information can be stored and different event listeners can be notified according to different events.
         initApplicationEventMulticaster();

         // Subclasses reserved for AbstractApplicationContext are used to initialize other special bean s,
         // This method needs to be invoked before all single instance bean initialization.
         // For example, the Web container will initialize some beans (ThemeSource) related to topic presentation
         onRefresh();

         // Register listeners (check listener bean s and register them)
         registerListeners();

         //Set the custom type converter ConversionService,
         // Set the custom AOP related class loadtimeweaver aware,
         // Clear temporary ClassLoader
         // , instantiate all classes (except lazy loaded classes)
         finishBeanFactoryInitialization(beanFactory);

         // Initialize the lifecycle event processor of the container (defaultlifecycle processor is used by default), and call the start method that extends the SmartLifecycle interface
         // After the Spring container loads all bean s and completes initialization, it will then call back the corresponding method (start() method) in the class that implements the interface
         // And publish the container refresh event ContextRefreshedEvent to the corresponding event listener
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         //Destroy the created Bean
         destroyBeans();

         // Reset 'active' flag.
         //Cancel the refresh operation and reset the synchronization ID of the container
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset the shared cache in the Spring kernel, because we may no longer need the metadata of the singleton bean
         resetCommonCaches();
      }
   }
}

Summary of this chapter

Post Processors

Container level interface: container level generic beanfactoryprocessor, BeanDefinitionRegistryPostProcessor for bean registration,

Bean level interface: BeanPostProcessor

Split the event publisher into ApplicationEventPublisher, which is specially responsible for publishing events, and applicationeventmulticast, which has the functions of event publishing, listening and registration. The class implementing the interface is responsible for calling the listener to process the events published by the container implementing the ApplicationEventPublisher interface.

Topics: Java Spring mvc