beanFactory design pattern Bean lifecycle nonsense, haha

Write before

For Readers: With some experience, this article is not suitable for beginners because you may not understand what I am saying

Idea for the article: Bean's life cycle, source interpretation (lots of source code for you) won't start out like other blog posts.Personally, I think it should be driven by the problem, why the BeanFactory came out, why there was a life cycle.

text

We started with beans that were simple beans, like vo, po, entity, dto. That's how we play

XXEntity xxEntity = new XXEntity();
xxEntity.setPropA("Character string");

A more complex bean may appear later that has an object as an attribute and needs to be set at or after construction (example only, not true), such as

// Build a serialization instance, where Serializable is the interface. The advantage of using the interface is that you do not need to modify the jedis class when using other serializations
Serializable fastJsonSerizlizable = new FastJsonSerizlizable();

// To build the target jedis instance, you need to first build the serialized object 
Jedis jedis = new Jedis();
jedis.setSerializable(fastJsonSerizlizable);

Now comes the serviceA and serviceB classes, both of which need to use redis. I can't write the process of instantiating jedis once in each class. An experienced colleague will write a tool class to create jedis, like this

public BeanUtil {
    // You can take out the creation serialization sheet, because besides redis, kafka also needs serialization
    public static Serializable createSerializable(){
        return new FastJsonSerizlizable();
    }
    
    public static Jedis createJedis(){
        Jedis jedis = new Jedis();
        jedis.setSerializable(createSerializable());
        return jedis;
    }
}

// Here I can use createJedis for both serviceA and serviceB to get an instance of jedis directly without having to worry about creating details, which serialization to use, etc.

There are several problems with the code above

  • Jedis objects are created each time they are used, and each jedis object has a single Serializable object, but fastJson's serialization and jedis are just tools, one instance is enough.
  • Unable to configure Jedis
  • Users cannot be allowed to create BeanUtil instances, and the improved code is as follows
public BeanUtil {
    // Disable BeanUtil build 
    private BeanUtil(){}
    
    // Here we can use the bean's full path=> bean instance to cache the beans 
    static Map<String,Object> beansCache = new ConcurrentHashMap<String,Object>();
    
    static{
        // At initialization, instances of these bean s are cached in content because jedis relies on serializable, which needs to be created first
        Serializable serializable = createSerializable();
        beansCache.put(Serializable.class.getSimpleName(),serializable);
        Jedis jedis = createJedis();
        beansCache.put(jedis.class.getSimpleName(),jedis);
    }
    
    static Serializable createSerializable(String type){
        Serializable serializable =  beansCache.get("serializable");
        if(serializable != null)return serializable;
        
        switch(type){
            case "kryo":    // kryo can't use singletons, please ignore this problem, examples only
                return new KryoSerializable();
            case "protostuff":
                return new protostuffSerializable();
            default:
                return new FastJsonSerizlizable();
        }
    }
    
    static Jedis createJedis(String serializableType){
        Jedis jedis = new Jedis();
        Serializable serializable = beansCache.get("serializable");
        jedis.setSerializable(serializable);
        return jedis;
    }

    //Then provide a way to get beans 
    public static Object getBean(String beanName){
        return beansCache.get(beanName);
    }
    
    public static T getBean(Class<T> type){
        return beansCache.get(type.getSimpleName());
    }

}

But if Xiao Ming writes this class, after a period of time there will be a large number of initialization operations of createXx and XX in this class, and the dependency is very complex. Then Xiao Ming thinks it is time to optimize a wave, so Xiao Ming has come up with a solution that defines an xml syntax

Use the bean tag to define a bean, each bean has a unique id information, use property to define its properties, if complex property uses ref, parse this xml to get a complete bean dependency graph

<beans>
    <bean id="serializable" class="com.xx.FastJsonSerizlizable" />
    
    <bean id="jedis" class="com.xx.Jedis">
        <property name="host" value="localhost" />
        <property name="serializable" ref="serializable"/>
    </bean>
</beans>

There will be a dependency problem at this point. I create jedis to create serializable first, but the xml bean definition of serializable is written in front of the file. Smart idea is to save the ref using a string first, and put it all in one bean definition, like this

Map<String,BeanDefinition> beanDefinitions = new HashMap();

It is then parsed into a dependency tree, so that leaves can be constructed first, then objects can be constructed one by one, but there is also a tricky situation: circular dependency

root

  |-jedis

    |- serializable

What is circular dependency? The simplest A depends on B, B depends on A, or there are more dependencies in the middle that end up forming a circle, A-B-C-A

The original solution is that we can use constructors to create them all first, not with them, and then set the object through its properties.So in addition to constructing injections, circular dependencies can be resolved through attributes.

That's what happened to our BeanUtil. Think of it as a tool class instead of an entity class, Factory

public BeanFactory {
    
    Map<String,BeanDefinition> beanDefinitions = new HashMap();
    
    // Here we can use the bean's full path=> bean instance to cache the beans 
    Map<String,Object> beansCache = new ConcurrentHashMap<String,Object>();
 
    {
        // Load xml bean configuration file
        beanDefinitions = loadXml(contextConfigurations:String []);
        
        //Instantiate all bean s 
        beansCache = instanceBeans(beanDefinitions);
    }
    
    //Then provide a way to get beans 
    public  Object getBean(String beanName){
        return beansCache.get(beanName);
    }
    
    public  T getBean(Class<T> type){
        return beansCache.get(type.getSimpleName());
    }
}

This seems perfect enough, but then programmer A asks me, when I need to initialize a class of mine, I want to get some connection resources, file resources, and recycle resources when the class is destroyed, but there's nothing I can do about it.

Xiao Ming said, that's good. I'll provide you with several interfaces. If you do, I'll instantiate Bean. If I find you have an interface, I'll call it for you in the corresponding process, so Xiao Ming added two interfaces.

public interface InitializingBean{
    void afterPropertiesSet() throws Exception;
}

public     interface DisposableBean{
    void destroy() throws Exception;
}

Programmer A's problem was solved, and Programmer B said there was no way to intercept the initialization of all beans, not my current class. I wanted to change each service to a proxy class. I wanted to add transactions to the methods in the service.

Xiao Ming said, well, I injected all the properties of the bean, and then gave it to you, you decorated the bean and then returned it to me, so Xiao Ming provided an interface that you can modify the beans before and after the initialization of the beans. Don't be careful, this is for the global, not your personal beans, so do a good filtering operationdo

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException ;
    
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
}

Programmer c then asked again, I created a BeanA but how can I get BeanC? I want to see some properties of c.

The novel says,'That's annoying. I just gave you all map s. No, I gave you all BeanFactory, so I got this interface

public interface BeanFactoryAware{
    void setBeanFactory(BeanFactory beanUtil);
}

Program D then asks if the global processor I created executed when I was setBeanFactory or later, big head.

Xiao Ming said, I've sorted out the execution sequence and named it Bean's life cycle. By the way, I'll provide a few more useful interfaces. I haven't told you the name of the bean yet, so the sorted life cycle is as follows

Reflection Create Bean 
Fill Object Properties
BeanNameAware.setBeanName();
BeanFactoryAware.setBeanFactory ();
BeanPostProcessor.postProcessBeforeInitialization(); multiple
InitializingBean.afterPropertiesSet()
BeanPostProcessor.postProcessAfterInitialization(); multiple
DisposableBean.destory()

Programmer E adds that xml configuration is too cumbersome. Isn't jdk1.5 annotated? I add an identifier to the class. You scan my class and help me create an instance.

Then when I need to use it, I add an identifier to the attribute. You can also find dependent classes based on the type, create corresponding instances, and help me put values in. If the process of creating this class is complex, I will create it myself, and then I will return it to you. I define a method, add a Bean's identifier, and you will read into the container.

Xiao Ming then adds @Component to represent the component, @Bean to represent custom instance creation, @Autowired to inject object @PostConstruct to perform class initialization @PreDestroy to destroy the class, and the life cycle of the class becomes like this

Reflection Create Bean 
Fill Object Properties
BeanNameAware.setBeanName();
BeanFactoryAware.setBeanFactory ();
BeanPostProcessor.postProcessBeforeInitialization(); multiple
PostConstruct
InitializingBean.afterPropertiesSet()
BeanPostProcessor.postProcessAfterInitialization(); multiple
PreDestroy
DisposableBean.destory()

However, in order to be compatible with the previous xml format, Xiao Ming now abstracts BeanFactory as an interface and provides a getBean method. According to the principle of single responsibility, BeanFactory should no longer do the work of parsing beans.

Create another interface to load the Bean Definition, two implementations of XmlBeanRegistry, AnnotationBeanRegistry, load the Bean Definition and merge, providing an external interface at once, considering the possibility of adding other registered beans in the future

public interface BeanFactoryPostProcessor{
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

You can instantiate the beanDefinition that you wrote your rule into the BeanDefinition that I requested and send it to me to customize the implementation and add your custom beans to the container

A little promotion

It's not easy to create. I hope you can support my open source software and my gadgets. Welcome to gitee dot star, fork, bug-raising.

Excel Universal Import and Export, Supports Excel Formulas
Blog address: https://blog.csdn.net/sanri1993/article/details/100601578
gitee: https://gitee.com/sanri/sanri-excel-poi

Use template code to generate code from a database and widgets that are often used in some projects
Blog address: https://blog.csdn.net/sanri1993/article/details/98664034
gitee: https://gitee.com/sanri/sanri-tools-maven

Tags: Java Jedis xml Excel Attribute

Posted on Thu, 07 Nov 2019 08:17:53 -0800 by pfchin