This article has participated in the Denver Nuggets Creators Camp 3 “More Productive writing” track, see details: Digg project | creators Camp 3 ongoing, “write” personal impact.

Spring provides a series of interfaces to provide extensions to the Spring container. Below we introduce one by one.

BeanPostProcessor custom bean

As mentioned in the previous article in Custom Beans, you can implement Spring’s InitializingBean and DisposableBean interfaces to implement the life cycle of a custom bean. If container level, Spring provides a more powerful BeanPostProcessor to extend beans at the container level.

The BeanPostProcessor interface defines two methods:

	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
Copy the code

The method in the call container initialization methods (such as InitializingBean. AfterPropertiesSet () or any statement of the init method), before and after any bean initialization, is invoked.

	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
Copy the code

This method is called after the container initializes the method.

You can configure multiple Beanpostprocessors. If you want to control the order of multiple Beanpostprocessors, you can implement the Ordered interface to define their order.

Although BeanPostProcessor is automatically detected through ApplicationContext, you can also register it manually through addBeanPostProcessor in ConfigurableBeanFactory. If manually registered, its Ordered becomes invalid, and the order of manually registered shall prevail.

Also note that programmatically registered instances of BeanPostProcessor are always processed before being registered as auto-detected instances and do not receive any explicit ordering.

All Instances of BeanPostProcessor and beans directly referenced by those instances are instantiated at startup, because the AOP automatic proxy is implemented as BeanPostProcessor itself, So neither the BeanPostProcessor instances nor the beans they directly reference are eligible for automatic proxying.

Here is an example of a call:

    <bean id="beanA" class="com.flydean.beans.BeanA"/>
    <bean id="beanB" class="com.flydean.beans.BeanB"/>

    <bean class="com.flydean.beans.InstantiationTracingBeanPostProcessor"/>
Copy the code

Call implementation:

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-post-processor.xml");
        BeanA beanA = (BeanA) ctx.getBean("beanA");
        System.out.println(beanA);
    }
Copy the code

BeanFactoryPostProcessor customizes configuration metadata

The semantics of the BeanFactoryPostProcessor interface are similar to those of the BeanPostProcessor, with one major difference: The BeanFactoryPostProcessor operates on Bean configuration metadata. That is, the Spring IOC container allows the BeanFactoryPostProcessor to read configuration metadata and possibly make changes to it before the container instantiates any beans other than the BeanFactoryPostProcessor instance.

The BeanFactoryPostProcessor can also be configured in more than one way, implementing the Ordered interface to determine the order of execution. BeanFactoryPostProcessor defines a method:

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
Copy the code

This method lets you get a configurable beanFactory to modify the bean definition.

Spring provides many predefined bean factory after processor, such as PropertyOverrideConfigurer and accomplished. Here’s an example of how to use it.

PropertyOverrideConfigurer replace the name of the class

Is accomplished mainly used for the Property from the external file read attributes, used to replace a defined configuration, such doing can make personnel application deployment of custom attributes specific to the environment, such as a database URL and password, Without adding complexity or risk by modifying one or more XML definition master files for the container.

Here is the configured XML file:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath:jdbc.properties"/>
    </bean>

    <bean id="dataSource" destroy-method="close"
          class="com.flydean.beans.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
Copy the code

This example shows that Properties are configured in an external Properties file. At runtime, use is accomplished some of metadata substitution into the DataSource attribute. The value to be replaced is specified as a placeholder for the ${property-name} format, which follows ant and Log4J as well as JSP EL styles.

The actual values are taken from an external Java Properties file:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
Copy the code

PropertyOverrideConfigurer properties covered

PropertyOverrideConfigurer can be used to override the default value of Bean properties, or set a new value. Let’s look at an example:

    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations" value="classpath:override.properties"/>
        <property name="properties">
            <value>beanOverride.url=com.something.DefaultStrategy</value>
        </property>
    </bean>
    <bean name="beanOverride" class="com.flydean.beans.BeanOverride"/>
Copy the code

The corresponding class is:

@Data
public class BeanOverride {

    private String name="beanA";
    private String url="http://www.163.com";

}
Copy the code

Its default properties are overwritten.

Custom instantiation logic using FactoryBeans

The FactoryBean interface provides three methods:

  • Object getObject(): Returns the instance created by the factory, which may be shared depending on whether the instance is a singleton or multi-instance pattern.
  • Boolean isSingleton(): Determine whether a FactoryBean returns a singleton or multiple instances.
  • Class getObjectType(): Returns the type returned by getObject(), or null if the type is not known in advance.

We can implement the FactoryBean interface to customize the implementation logic of the Bean.

public class BeanFactoryBean implements FactoryBean {

    @Resource
    private BeanA beanA;

    @Override
    public Object getObject(a) throws Exception {
        return beanA;
    }

    @Override
    publicClass<? > getObjectType() {returnBeanA.class; }}Copy the code

Here is its configuration:

    <context:annotation-config/>
    <bean id="beanA" class="com.flydean.beans.BeanA"/>

    <bean id="beanFactoryBean" class="com.flydean.beans.BeanFactoryBean"/>
Copy the code

How to use it?

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-factory.xml");
        BeanFactoryBean beanFactoryBean = (BeanFactoryBean) ctx.getBean("&beanFactoryBean");
        System.out.println(beanFactoryBean.getObject());
        System.out.println(beanFactoryBean.getObjectType());

        BeanA beanA=(BeanA)ctx.getBean("beanFactoryBean");
        System.out.println(beanA);
    }
Copy the code

When you need to request the actual FactoryBean instance itself from the container rather than the bean it generated, you prefix the bean ID with the symbol (&) when you call the GetBean () method of the ApplicationContext. So, for a given FactoryBean with ID beanFactoryBean, calling getBean (” beanFactoryBean “) on the container returns the bean generated by the FactoryBean, Calling getBean (” &beanFactoryBean “) returns the FactoryBean instance itself.

See ioc-extend for examples in this section

See flydean’s blog for more tutorials