Read the official document together ---- spring IOC (06)

1.6. Properties of custom bean s

The Spring framework provides many interfaces that can be used to customize the nature of beans. This section groups them as follows:

  • Lifecycle Callbacks
  • ApplicationContextAware and BeanNameAware
  • Other Aware
1.6.1. Lifecycle Callback

In order to manage the bean life cycle with the participating container, you can implement Spring's InitializingBean and DisposableBean interfaces.
Container initialization calls the afterpropertieset () method and destruction calls the destroy() method to perform some operations.

Usually,@PostConstruct and@PreDestroy Annotations are considered in Spring Best practices for receiving lifecycle callbacks in applications.
Using these annotations means your bean Not coupled to specific Spring Interface for.

If you don't want to use JSR-250 Annotation, but you still have to remove the coupling, consider init-method and destroy-methodbean Define metadata.


public class InitAndDestroyBean implements InitializingBean, DisposableBean {
	@Override
	public void destroy() throws Exception {
		System.out.println("DisposableBean destroy");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("InitializingBean init" );
	}

	@PostConstruct
	public void init(){
		System.out.println("PostConstruct init");
	}

	@PreDestroy
	public void destroy2(){
		System.out.println("PreDestroy destroy");
	}

	public void initMethod(){
		System.out.println("Init-method init");
	}

	public void destroyMethod(){
		System.out.println("Destroy-method destroy");
	}
}


	<bean id="initAndDestroyBean" class="org.springframework.example.lifecycle.InitAndDestroyBean"
	init-method="initMethod" destroy-method="destroyMethod">

Console printing:
    PostConstruct init
    InitializingBean init
    Init-method init
    .
    .
    .
    PreDestroy destroy
    DisposableBean destroy
    Destroy-method destroy

Internally, the Spring framework uses the BeanPostProcessor implementation to handle any callback interface it can find and call the appropriate methods. If you need custom functions or other life cycle behaviors that Spring does not provide by default, you can implement them yourself by BeanPostProcessor.

In addition to initializing and destroying callbacks, spring managed objects can also implement the Lifecycle interface so that these objects can participate in the startup and shutdown process, which is driven by the container's own Lifecycle.

Above Lifecycle There is such a comment on the class
 * <p>Note that the present {@code Lifecycle} interface is only supported on
 * <b>top-level singleton beans</b>. On any other component, the {@code Lifecycle}
 * interface will remain undetected and hence ignored. Also, note that the extended
 * {@link SmartLifecycle} interface provides sophisticated integration with the
 * application context's startup and shutdown phases.
 
 Did you understand it at first top-level singleton beans I tried to realize it myself Lifecycle
 @Component
 public class CustomLifecycle implements Lifecycle {
	@Override
	public void start() {
		System.out.println("start-----------");
	}

	@Override
	public void stop() {
		System.out.println("stop-----------");
	}
	@Override
	public boolean isRunning() {
		return false;
	}
}

console output 
PostConstruct init
InitializingBean init
Init-method init
PreDestroy destroy
DisposableBean destroy
Destroy-method destroy

These codes don't work
 Debugged the source code and found that the container did find when starting and closing the container Lifecycle All the implementation classes, but there's another one if operation
if (bean instanceof SmartLifecycle) {
    .
    .
    .
}
Inheritance relationship changed
@Component
public class CustomSmartLifecycle implements SmartLifecycle {
	@Override
	public void start() {
		System.out.println("start-----------");
	}

	@Override
	public void stop() {
		System.out.println("stop-----------");
	}
	@Override
	public boolean isRunning() {
		return false;
	}
}

console output 
PostConstruct init
InitializingBean init
Init-method init
start-----------
PreDestroy destroy
DisposableBean destroy
Destroy-method destroy

This is a little understanding of the comment, which probably means that if you inherit directly from Lifecycle Interface,
Then the container will not call your custom interface, only inheritance SmartLifecycle Just do it
This section describes the lifecycle callback interface.
Initialize callback

org. springframework. beans. factory. The initializingbean interface allows the container to perform initialization after setting all necessary properties on the bean.

The InitializingBean interface specifies a method:

void afterPropertiesSet() throws Exception;

We recommend that you do not use this InitializingBean interface because it couples your code to Spring.
In addition, we recommend using the @ PostConstruct annotation or specifying the POJO initialization method.
For XML based configuration metadata, you can use the init method attribute to specify the name of a method with an invalid nonparametric signature.
Through Java configuration, you can use the initMethod attribute @ Bean.

See receiving lifecycle callbacks. Consider the following examples:

public class ExampleBean {
        public void init() {
            // do some initialization work
        }
}
You can use xml
    <bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
perhaps JAVA Bean to configure
	@Bean(initMethod = "init")
	public void exampleBean(){
		return new ExampleBean();
	}

The previous example has almost the same effect as the following example:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>

public class AnotherExampleBean implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
        // do some initialization work
    }
}

However, the first of the first two examples does not couple the code to Spring.

Destroy callback

org.springframework.beans.factory.DisposableBean when the container containing this interface is destroyed, implementing this interface allows the Bean to get a callback.

The DisposableBean interface specifies a method:

void destroy() throws Exception;

We recommend that you do not use the DisposableBean callback interface because it couples your code to Spring.
In addition, we recommend using the @ PreDestroy annotation or specifying the general methods supported by the bean definition.
When using XML based configuration metadata, you can use attributes on destroy method.
Through Java configuration, you can use the destroyMethod attribute @ Bean.
Consider the following definitions:

public class ExampleBean {
    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}

You can use xml
    <bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>

perhaps JAVA Bean to configure
	@Bean(destroyMethod = "cleanup")
	public void exampleBean(){
		return new ExampleBean();
	}

The previous definition has almost the same effect as the following definition:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>

public class AnotherExampleBean implements DisposableBean {
    @Override
    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}

However, the first of the first two definitions does not couple code to Spring.

You can<bean>Elemental destroy-method Property specifies a special(inferred)Value,
This value indicates Spring Automatically detect specific bean Public on class close or shutdown Method (any implementation) java.lang.AutoCloseable or java.io.Closeable Will also match). 

@Component
public class CustomAutoCloseable implements AutoCloseable {
	@Override
	public void close() {
		System.out.println("AutoCloseable close");
	}
}

@Component
public class CustomCloseable implements Closeable {
	@Override
	public void close()  {
		System.out.println("Closeable close");
	}
}

Console output:
    Closeable close
    AutoCloseable close
    
You can also<beans>Elemental default-destroy-method Property(inferred)Value,
To apply this behavior to the entire bean Gather.
<beans default-destroy-method="destroy" default-init-method="init"></beans>
Default initialization and destruction methods

When you write specific methods that initialize and destroy InitializingBean and DisposableBean callback interfaces that do not use specific spring,
You usually write methods with names such as init(), initialize(), dispose().
Ideally, the name of this lifecycle callback method is standardized throughout the project,
So that all developers can use the same method name and ensure consistency.

You can configure the Spring container to "find" the named initialization and destroy the callback method name on each bean.
This means that, as an application developer, you can write an application class and use an initialization callback called init(), without having to configure the init method = "init" attribute for each bean definition.
The Spring IoC container calls this method when creating a bean (and is consistent with the standard lifecycle callback contract described earlier). This feature also enforces consistent naming conventions for initialization and destruction method callbacks.

Suppose your initialization callback method is named init(), and your destroy callback method is named destroy(). Then, your class looks like the class in the following example:

public class DefaultBlogService implements BlogService {

    private BlogDao blogDao;

    public void setBlogDao(BlogDao blogDao) {
        this.blogDao = blogDao;
    }

    // this is (unsurprisingly) the initialization callback method
    public void init() {
        if (this.blogDao == null) {
            throw new IllegalStateException("The [blogDao] property must be set.");
        }
    }
}

You can then use this class in beans similar to:

<beans default-init-method="init">
    <bean id="blogService" class="com.something.DefaultBlogService">
        <property name="blogDao" ref="blogDao" />
    </bean>
</beans>

The default init method attribute appearing in the top-level element attribute will cause the Spring IoC container to recognize the method named init in the bean class as the initialization method callback.
When creating and assembling beans, if the bean class has such a method, it will be called at the appropriate time.

You can use the default destroy method attribute on the top-level element to configure the destroy method callback (that is, in XML).

If the existing bean class already has a callback method named according to the Convention, you can override the default value by specifying (in XML, that is) the method name by using its own init method and destroy method attributes.

Spring The container is guaranteed to be bean The configured initialization callback is called immediately after all dependencies are provided.  
Therefore, the initialization callback is in the original bean The reference is called, which means AOP Interceptors and so on have not been applied to bean.   
therefore AOP The order of execution is to create a target first bean´╝îThen apply a chain with interceptors AOP agent(for example).  
Therefore, the interceptor is applied to init The method is not applicable.
Combined life cycle mechanism

Starting with Spring 2.5, you can use three options to control Bean life cycle behavior:

  • InitializingBean and DisposableBean callback interfaces
  • Customize init() and destroy() methods
  • Comments in @ PostConstruct and @ PreDestroy.
    You can combine these mechanisms to control a given bean.

If multiple lifecycle mechanisms are configured for a bean and different method names are configured for each mechanism, each configured method will run in the order listed after this comment.
However, if init() has both the @ PostConstruct annotation and the xml init method method, the init() method will be executed once.

Using different initialization methods, multiple life cycle mechanisms configured for the same bean are as follows:
Calling order of initialization method:

  • Use annotation method @ PostConstruct
  • Initializepartiphereset() is defined by the callback
  • init() method of custom configuration

The destruction methods are called in the same order:

  • Use annotation method @ PreDestroy
  • destroy() is defined by the DisposableBean callback interface
  • Custom configured destroy() method
Startup and shutdown callback

The Lifecycle interface defines basic methods for any object with Lifecycle requirements, such as starting and stopping some background processes:

public interface Lifecycle {
    void start();
    void stop();
    boolean isRunning();
}

Any Spring managed object can implement the Lifecycle interface.
Then, when the ApplicationContext itself receives start and stop signals (for example, for a stop / restart scenario at runtime), it cascades these calls into all implementations defined in the context of Lifecycle.
It is delegated to lifecycle processor through, as shown in the following list:

public interface LifecycleProcessor extends Lifecycle {
    void onRefresh();
    void onClose();
}

Note that the Lifecycle processor itself is an extension of the Lifecycle interface. It also adds two other methods to respond to the context being refreshed and closed.

Please note that general org springframework. context. The lifecycle interface is a common protocol for explicit start and stop notifications, and does not mean that it is started automatically when the context is refreshed. For fine-grained control over the automatic startup of a specific bean (including the startup phase), consider implementing org springframework. context. SmartLifecycle.

Also, please note that there is no guarantee that a stop notice will be issued before destruction. During normal shutdown, all beans will first receive a stop notification before Lifecycle propagates the normal destruction callback. However, when you make a hot refresh or stop a refresh attempt during the context Lifecycle, only the destroy method is called.

The order in which calls are started and closed can be important.
If there is a "dependency" relationship between any two objects, the relying party starts after its dependency and stops before the dependency.
However, sometimes the direct dependencies are unknown.
You may only know that objects of one type should start before objects of another type.
In these cases, the SmartLifecycle interface defines another option, the getPhase() method defined on its interface Phased.
The following listing shows the definition of the Phased interface:

public interface Phased {
    int getPhase();
}

The following list shows the definition of the SmartLifecycle interface:

public interface SmartLifecycle extends Lifecycle, Phased {

    boolean isAutoStartup();
    void stop(Runnable callback);
}

When starting, the object with the lowest phase starts first.
When stopping, follow the reverse order.
Therefore, implement SmartLifecycle and getPhase() returns the object integer of its method MIN_ Value will be the first to start and the last to stop.
At the other end of the spectrum, the phase value is integer MAX_ Value indicates that the object should be started last and stopped first (possibly because the object depends on other running processes).
When considering the phase value, it is also important to know that for any "normal" default phase, the Lifecycle goal does not achieve the 0 of SmartLifecycle.
Therefore, any negative phase value indicates that the object should start before (and stop after) these standard components. For any positive phase value, vice versa.

The stop method of SmartLifecycle accepts Runnable callback as the method input parameter.

    default void stop(Runnable callback) {
		stop();
		callback.run();
	}

After the implementation of the subclass of stop() is completed, call the callback Method of run().

Because the default implementation of the LifecycleProcessor interface DefaultLifecycleProcessor will wait for its timeout value in each stage to call the callback, you can enable asynchronous shutdown if necessary.

The default timeout for each phase is 30 seconds.
You can override the default lifecycle processor instance by defining named bean s in the lifecycle processor context.
If you only want to modify the timeout, you can define the following:

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

As mentioned earlier, the lifecycle processor interface also defines callback methods to refresh and close the context.
The latter drives the closing process as if stop() were explicitly called, but it happens when the context is closed.
On the other hand, "Refresh" callback can implement another feature of SmartLifecycle bean.
When the context is refreshed (after all objects are instantiated and initialized), the callback is called.
At this point, the default lifecycle processor checks the Boolean value returned by the isAutoStartup() method of each SmartLifecycle object.
If true, start the object at that point instead of waiting for the context or its own explicit call to the start() method (unlike context refresh, context startup does not occur automatically for standard context implementations).
As mentioned above, the phase value and any "dependency" relationship determine the start-up sequence.

    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
		Map<Integer, LifecycleGroup> phases = new HashMap<>();
		lifecycleBeans.forEach((beanName, bean) -> {
		    //DefaultLifecycleProcessor calls this method autoStartupOnly and is never true
		    //If the bean instanceof smartlifecycle and the isAutoStartup() method returns true
			if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
				int phase = getPhase(bean);
				LifecycleGroup group = phases.get(phase);
				if (group == null) {
					group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
					phases.put(phase, group);
				}
				group.add(beanName, bean);
			}
		});
		if (!phases.isEmpty()) {
			List<Integer> keys = new ArrayList<>(phases.keySet());
			Collections.sort(keys);
			for (Integer key : keys) {
				phases.get(key).start();
			}
		}
	}
Close the Spring IoC container normally in non Web applications

This section applies only to non Web applications.
Spring's Web-based ApplicationContext implementation has the corresponding code, which can normally close the Spring IoC container when the relevant Web application is closed.

If you are using Spring's IoC container in a non web application environment (for example, in a rich client desktop environment), register a shutdown hook with the JVM.
This ensures an elegant shutdown and calls the relevant destruction methods on the singleton bean, freeing up all resources.
You must still configure and implement these destruction callbacks correctly.

To register a shutdown hook, call the registerShutdownHook() method, which is declared on the ConfigurableApplicationContext interface, as shown in the following example:

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Boot {

    public static void main(final String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

        // add a shutdown hook for the above context...
        ctx.registerShutdownHook();

        // app runs here...

        // main method exits, hook is called prior to the app shutting down...
    }
}
1.6.2. ApplicationContextAware and BeanNameAware

When ApplicationContext creates an implementation org springframework. context. When an object instance of applicationcontextaware is, the instance provides a reference to ApplicationContext. The following listing shows the definition of the applicationcontext taware interface:

public interface ApplicationContextAware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

Therefore, bean s can operate programmatically to create their ApplicationContext through the ApplicationContext interface or by converting references to known subclasses of the interface (such as ConfigurableApplicationContext, which exposes other functions).
One use is to programmatically retrieve other bean s.
Sometimes this function is useful.
However, it should generally be avoided because it combines code with Spring and does not follow the control inversion style, in which collaborators are provided to bean s as properties.
Other methods of ApplicationContext provide access to file resources, publishing application events, and accessing message sources.
These additional features are described in the additional functions of ApplicationContext.

Auto assembly is another option to get a reference to ApplicationContext.
The traditional constructor and byType automatic assembly modes can provide the dependency of type ApplicationContext for constructor parameters or setter method parameters respectively.

For greater flexibility, including the ability to automatically assemble fields and multiple parameter methods, annotation based automatic assembly features can be used. If you do, ApplicationContext will automatically generate a field, constructor parameter or method parameter. If the field, constructor or method in question is annotated with @ Autowired, these parameters are expected to get the ApplicationContext type.

After talking for a long time, it's better to look at the code:
public class CustomAutowiringApplicationContext {
	@Autowired
	private ApplicationContext applicationContext;

	public CustomAutowiringApplicationContext(ApplicationContext applicationContext){
		System.out.println(applicationContext);
	}

	public void setApplicationContext(ApplicationContext applicationContext){
		System.out.println(applicationContext);
	}
}
//Only byType or byName set injection can take effect
<bean id="customAutowiringApplicationContext"
		  autowire="byType"
		  class="org.springframework.example.applicationcontext.CustomAutowiringApplicationContext"/>

When ApplicationContext creates an implementation org springframework. beans. factory. Class of BeanNameAware. BeanNameAware interface, which provides a reference to the name of the current bean. The following listing shows the definition of the BeanNameAware interface:

public interface BeanNameAware {
    void setBeanName(String name) throws BeansException;
}

Source code:
    private void invokeAwareMethods(String beanName, Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}
Execution sequence source code:
    if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			    //Handle aware as above
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
		    //Execute initialization methods, such as InitializingBean, afterpropertieset, or custom init method
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

BeanNameAware, BeanClassLoaderAware, BeanFactoryAware are executed after filling in common bean properties, but before initializing callbacks (such as InitializingBean, afterpropertieset, or custom init method).

1.6.3. Other Aware interfaces

In addition to applicationcontext taware and beannameaware (discussed earlier), Spring also provides a wide range of perceptible callback interfaces that allow beans to indicate to containers that they need some infrastructure dependency. As a general rule, names represent dependency types. The following table summarizes the most important perceptual interfaces:

Table 4 Many aware interfaces have not been used, so it is impossible to explain them in detail. They will be added later. Here is a brief list
name Injected object
ApplicationContextAware ApplicationContext
ApplicationEventPublisherAware Event publisher ApplicationContext
BeanClassLoaderAware Class loader, used to load Bean classes.
BeanFactoryAware BeanFactory
BeanNameAware The name of the bean.
BootstrapContextAware The resource adapter in which the BootstrapContext container runs.
Usually available only in ApplicationContext instances that support JCA.
LoadTimeWeaverAware Defines the weaver that handles class definitions at load time
MessageSourceAware Configured policy for resolving messages (supports parameterization and internationalization)
NotificationPublisherAware Spring JMX notifies Publishers
ResourceLoaderAware Configured policy for parsing messages (supports parameterization and internationalization)
ServletConfigAware Currently, the ServletConfig container is running in it.
Run only in WebApplicationContext environment
ServletContextAware Currently, the ServletContext container is running in it.
Run only in WebApplicationContext environment

Again, notice that using these interfaces binds your code to the Spring API and does not follow the "inversion of control" style. Therefore, we recommend using them for infrastructure beans that need to access containers programmatically.

1.7. Bean Definition inheritance

Bean definitions can contain many configuration information, including constructor parameters, attribute values, and container specific information, such as initialization methods, static factory method names, and so on. The child bean definition inherits configuration data from the parent bean definition. Child definitions can override some values or add other values as needed. Using parent and child bean definitions can save a lot of input. In fact, this is a form of template.

If you use the ApplicationContext interface programmatically, the sub bean definition is represented by the ChildBeanDefinition class. Most users will not use them at this level. Instead, they declaratively configure bean definitions in classes such as classpathxmlapplicationcontext. When you use xml based configuration metadata, you can indicate the child bean definition by using the parent attribute and specify the parent bean as the value of the attribute. The following example shows how to do this:

<bean id="inheritedTestBean" abstract="true"
        class="org.springframework.beans.TestBean">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithDifferentClass"
        class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBean" init-method="initialize">  
        <!-- be careful parent attribute -->
    <property name="name" value="override"/>
    <!--age Property inherits the parent class-->
</bean>

If the class attribute of the bean is not specified, the child bean definition uses the class of the bean in the parent definition, but it can also be overridden. In the latter case, the child bean class must be compatible with the parent bean (that is, it must accept the property value of the parent bean).

The child bean definition inherits the scope, constructor parameter value and attribute value from the parent bean, overrides the parent class method, and provides the option to add a new value.
Any Scope, initialization method, destroy method, or static factory method settings you specify override the corresponding parent settings.

The rest of the settings are always taken from sub definitions: dependency, auto assembly mode, dependency check, singleton and lazy init.

The previous example explicitly marks the parent bean definition as abstract by using abstract properties. If the parent definition does not specify a class, you need to explicitly mark the parent bean definition as abstract, as shown in the following example:

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBeanWithoutClass" init-method="initialize">
    <property name="name" value="override"/>
     <!--age Property inherits the parent class-->
</bean>

The parent bean cannot instantiate itself because it is incomplete and it is explicitly marked as abstract. When the definition is abstract, it can only be used as a pure template bean definition and as the parent of the child definition. Trying to use such an abstract parent bean alone, by referring to it as the ref attribute of another bean, or by using the parent bean ID to make an explicit getBean() call, will return an error. Similarly, the container's internal pre instantiation esingletons() method ignores bean definitions that are defined as abstractions.

By default, ApplicationContext Pre instantiate all singletons.
therefore,If you have one(father)bean Define what you only intend to use as a template,
And this father bean The definition specifies a class,You must ensure that the abstract property is set to true,
Otherwise, the application context will(try)Pre instantiation abstract of bean. 

This article is composed of blog one article multi posting platform OpenWrite release!

Posted by ify on Sun, 15 May 2022 19:15:11 +0300