1
头图

Author: Xiao Fu Ge
Blog: https://bugstack.cn

Precipitate, share, and grow, so that you and others can gain something! 😄

I. Introduction

colleague wrote the code, I can't understand it at all!

Big guy’s code is like "Like a toad bubble frog, Zhang’s ugly flower" : A class implements multiple interfaces, inherited classes inherit other classes, and interfaces can also inherit and implement interfaces. The abstract class then implements the abstract class method, the class B inherited by the class A realizes the interface C realized by the class A, and so on.

It seems that complex and difficult to understand, but it can meet the needs of efficient iteration and smooth expansion again and again, and you who move bricks like a screw, you just complete a certain interface in the code written by Small blocks of functions are called and run even after they are written. The whole process is as magical as looking at the Spring source code. I can't figure out the clue when I jump around!

In fact, this is mainly because of whether your code uses design patterns. Of course, the design patterns are not that magical. Just like your two houses are 120 square meters, his family has three bedrooms, two halls, one kitchen and one bathroom. The north and south are transparent. Sunlighting. But your home is different. Your home is made up of pots and pans, bathroom toilets, sofas and coffee tables, and the 1.8 double bed. They are opened in a 120 square meter house. There is no isolation between movement and static, and no separation of dry and wet. Free to play. so your code looks messy!

2. Goal

The Spring framework that has been implemented so far can provide capabilities in Bean operations, including: the definition and registration of Bean objects, as well as those executed in the process of operating Bean objects, BeanFactoryPostProcessor, BeanPostProcessor, InitializingBean, DisposableBean, and new additions in XML Some configuration processing allows us to have stronger operability for the Bean object.

So, if we want to obtain the BeanFactory, ApplicationContext, BeanClassLoader and other capabilities provided by the Spring framework, what should we do when using some extended frameworks? Therefore, in this chapter, we hope to provide an interface that can perceive container operations in the Spring framework. If anyone implements such an interface, he can obtain various capabilities in the interface parameters.

Three, design

If I want to get some of the resources provided in the Spring framework, then I first need to consider how to obtain them, and then how you define the method of obtaining them in the Spring framework, and how to implement these two contents, just You can expand some of the capabilities you need that belong to the Spring framework itself.

In the phase of instantiation of the Bean object, we have operated some additional definitions, attributes, initialization and destruction operations. In fact, if we get Spring, such as BeanFactory and ApplicationContext, we can also implement it in this way. Then we need to define a marked interface, this interface does not need to have methods, it can only serve as a marking function, and the specific function is defined by other functional interfaces that inherit this interface. Finally, this interface can pass instanceof Judgment and call are made. The overall design structure is as follows:

  • Define the interface Aware. In the Spring framework, it is a mark-aware interface. Specific subclass definitions and implementations can be aware of related objects in the container. also through this bridge to provide container services to specific implementation classes
  • The interfaces that inherit Aware include: BeanFactoryAware, BeanClassLoaderAware, BeanNameAware, and ApplicationContextAware. Of course, there are some other annotations in the Spring source code, but we still don't use them at present.
  • In the specific interface implementation process, you can see that part of ( BeanFactoryAware, BeanClassLoaderAware, BeanNameAware ) is in the support folder of the factory, and ApplicationContextAware is in the support of the context. This is because different content acquisition needs to be in different Provided under the package. ApplicationContextAwareProcessor operation of adding BeanPostProcessor content to beanFactory will be used in the specific implementation of AbstractApplicationContext, and finally the corresponding call operation will be processed when createBean is created by AbstractAutowireCapableBeanFactory. About applyBeanPostProcessorsBeforeInitialization has been implemented in the previous chapter, if you forget, you can look forward to

Fourth, realize

1. Engineering structure

small-spring-step-08
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework
    │           ├── beans
    │           │   ├── factory
    │           │   │   ├── factory
    │           │   │   │   ├── AutowireCapableBeanFactory.java
    │           │   │   │   ├── BeanDefinition.java
    │           │   │   │   ├── BeanFactoryPostProcessor.java
    │           │   │   │   ├── BeanPostProcessor.java
    │           │   │   │   ├── BeanReference.java
    │           │   │   │   ├── ConfigurableBeanFactory.java
    │           │   │   │   └── SingletonBeanRegistry.java
    │           │   │   ├── support
    │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   │   ├── AbstractBeanDefinitionReader.java
    │           │   │   │   ├── AbstractBeanFactory.java
    │           │   │   │   ├── BeanDefinitionReader.java
    │           │   │   │   ├── BeanDefinitionRegistry.java
    │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java
    │           │   │   │   ├── DefaultListableBeanFactory.java
    │           │   │   │   ├── DefaultSingletonBeanRegistry.java
    │           │   │   │   ├── DisposableBeanAdapter.java
    │           │   │   │   ├── InstantiationStrategy.java
    │           │   │   │   └── SimpleInstantiationStrategy.java  
    │           │   │   ├── support
    │           │   │   │   └── XmlBeanDefinitionReader.java
    │           │   │   ├── Aware.java
    │           │   │   ├── BeanClassLoaderAware.java
    │           │   │   ├── BeanFactory.java
    │           │   │   ├── BeanFactoryAware.java
    │           │   │   ├── BeanNameAware.java
    │           │   │   ├── ConfigurableListableBeanFactory.java
    │           │   │   ├── DisposableBean.java
    │           │   │   ├── HierarchicalBeanFactory.java
    │           │   │   ├── InitializingBean.java
    │           │   │   └── ListableBeanFactory.java
    │           │   ├── BeansException.java
    │           │   ├── PropertyValue.java
    │           │   └── PropertyValues.java 
    │           ├── context
    │           │   ├── support
    │           │   │   ├── AbstractApplicationContext.java 
    │           │   │   ├── AbstractRefreshableApplicationContext.java 
    │           │   │   ├── AbstractXmlApplicationContext.java 
    │           │   │   ├── ApplicationContextAwareProcessor.java 
    │           │   │   └── ClassPathXmlApplicationContext.java 
    │           │   ├── ApplicationContext.java 
    │           │   ├── ApplicationContextAware.java 
    │           │   └── ConfigurableApplicationContext.java
    │           ├── core.io
    │           │   ├── ClassPathResource.java 
    │           │   ├── DefaultResourceLoader.java 
    │           │   ├── FileSystemResource.java 
    │           │   ├── Resource.java 
    │           │   ├── ResourceLoader.java 
    │           │   └── UrlResource.java
    │           └── utils
    │               └── ClassUtils.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   ├── UserDao.java
                │   └── UserService.java
                └── ApiTest.java

project source code : public account "bugstack wormhole stack", reply: Spring column, get the complete source code

Spring aware interface design and implementation class relationship, as shown in Figure 9-2

图 9-2

  • The entire class relationship above is about the definition of Aware perception and the realization of container perception.
  • Aware has four inherited interfaces. The inheritance of these other interfaces is to inherit a mark. The existence of a mark makes it easier to operate and implement specific judgments.
  • In addition, because ApplicationContext is not the content under the createBean method in AbstractAutowireCapableBeanFactory, it is necessary to register addBeanPostProcessor container, and then operate when applyBeanPostProcessorsBeforeInitialization is called uniformly by createBean.

2. Define the markup interface

cn.bugstack.springframework.beans.factory.Aware

/**
 * Marker superinterface indicating that a bean is eligible to be
 * notified by the Spring container of a particular framework object
 * through a callback-style method.  Actual method signature is
 * determined by individual subinterfaces, but should typically
 * consist of just one void-returning method that accepts a single
 * argument.
 *
 * 标记类接口,实现该接口可以被Spring容器感知
 *
 */
public interface Aware {
}
  • In Spring, there are a lot of design methods for marking interfaces like this. Their existence is like a kind of label. It is convenient to extract the implementation classes belonging to this type of interface in a unified manner. Instanceof is usually used together to judge and use.

3. Container Awareness

3.1 BeanFactoryAware

cn.bugstack.springframework.beans.factory.BeanFactoryAware

public interface BeanFactoryAware extends Aware {

   void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}
  • Interface to be implemented by beans that wish to be aware of their owning {@link BeanFactory}.
  • By implementing this interface, you can perceive the BeanFactory you belong to

3.2 BeanClassLoaderAware

cn.bugstack.springframework.beans.factory.BeanClassLoaderAware

public interface BeanClassLoaderAware extends Aware{

    void setBeanClassLoader(ClassLoader classLoader);

}
  • Callback that allows a bean to be aware of the bean{@link ClassLoader class loader}; that is, the class loader used by the present bean factory to load bean classes.
  • To implement this interface, you can perceive the ClassLoader to which it belongs

3.3 BeanNameAware

cn.bugstack.springframework.beans.factory.BeanNameAware

public interface BeanNameAware extends Aware {

    void setBeanName(String name);

}
  • Interface to be implemented by beans that want to be aware of their bean name in a bean factory.
  • By implementing this interface, you can perceive the BeanName you belong to

3.4 ApplicationContextAware

cn.bugstack.springframework.context.ApplicationContextAware

public interface ApplicationContextAware extends Aware {

    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}
  • Interface to be implemented by any object that wishes to be notifiedof the {@link ApplicationContext} that it runs in.
  • To implement this interface, you can perceive the ApplicationContext to which it belongs

4. Packaging Processor (ApplicationContextAwareProcessor)

cn.bugstack.springframework.context.support.ApplicationContextAwareProcessor

public class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ApplicationContext applicationContext;

    public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ApplicationContextAware){
            ((ApplicationContextAware) bean).setApplicationContext(applicationContext);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}
  • Since the ApplicationContext cannot be obtained directly when the Bean is created, it is necessary to write the ApplicationContext into a wrapped BeanPostProcessor during the refresh operation, and then be called by the AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization method.

5. Register BeanPostProcessor

cn.bugstack.springframework.context.support.AbstractApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    @Override
    public void refresh() throws BeansException {
        // 1. 创建 BeanFactory,并加载 BeanDefinition
        refreshBeanFactory();

        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
        invokeBeanFactoryPostProcessors(beanFactory);

        // 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        // 6. 提前实例化单例Bean对象
        beanFactory.preInstantiateSingletons();
    }
    
     // ...   
}    
  • The refresh() method is the operation process of the entire Spring container. Compared with the previous chapter, the operation of addBeanPostProcessor has been newly added this time.
  • Add ApplicationContextAwareProcessor, so that bean objects inherited from ApplicationContextAware can be aware of the ApplicationContext they belong to.

6. Perceive call operation

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 给 Bean 填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 注册实现了 DisposableBean 接口的 Bean 对象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        addSingleton(beanName, bean);
        return bean;
    }

    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {

        // invokeAwareMethods
        if (bean instanceof Aware) {
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(this);
            }
            if (bean instanceof BeanClassLoaderAware){
                ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
            }
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
        }

        // 1. 执行 BeanPostProcessor Before 处理
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        // 执行 Bean 对象的初始化方法
        try {
            invokeInitMethods(beanName, wrappedBean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
        }

        // 2. 执行 BeanPostProcessor After 处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        return wrappedBean;
    }



    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (null == current) return result;
            result = current;
        }
        return result;
    }

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (null == current) return result;
            result = current;
        }
        return result;
    }

}
  • Here we have removed some of the content of the class, and only keep the operation about the Aware perception interface this time.
  • First, in initializeBean, by judging bean instanceof Aware , three interface methods are called, BeanFactoryAware.setBeanFactory(this) , BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader()) , BeanNameAware.setBeanName(beanName) , so that the classes that have implemented this interface can be notified.
  • In addition, we also added ApplicationContextAwareProcessor to the BeanPostProcessor. At this time, this method will also be called to the specific class implementation to get an ApplicationContex attribute.

Five, test

1. Prepare in advance

cn.bugstack.springframework.test.bean.UserDao

public class UserDao {

    private static Map<String, String> hashMap = new HashMap<>();

    public void initDataMethod(){
        System.out.println("执行:init-method");
        hashMap.put("10001", "小傅哥");
        hashMap.put("10002", "八杯水");
        hashMap.put("10003", "阿毛");
    }

    public void destroyDataMethod(){
        System.out.println("执行:destroy-method");
        hashMap.clear();
    }

    public String queryUserName(String uId) {
        return hashMap.get(uId);
    }

}

cn.bugstack.springframework.test.bean.UserService

public class UserService implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware {

    private ApplicationContext applicationContext;
    private BeanFactory beanFactory;

    private String uId;
    private String company;
    private String location;
    private UserDao userDao;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

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

    @Override
    public void setBeanName(String name) {
        System.out.println("Bean Name is:" + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("ClassLoader:" + classLoader);
    }

    // ...get/set
}
  • UserDao has not changed this time. It still provides a method for initialization, and provides init-method and destroy-method configuration information in Spring.xml.
  • UserService is newly added, BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware, four perceptual implementation classes, and implement the corresponding interface methods in the class.

2. Configuration file

basic configuration, no BeanFactoryPostProcessor, BeanPostProcessor, implementation class

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/>

    <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService">
        <property name="uId" value="10001"/>
        <property name="company" value="腾讯"/>
        <property name="location" value="深圳"/>
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>
  • There is no additional configuration information added in this chapter, which is the same as the previous chapter.

3. Unit Testing

@Test
public void test_xml() {
    // 1.初始化 BeanFactory
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    applicationContext.registerShutdownHook();      

    // 2. 获取Bean对象调用方法
    UserService userService = applicationContext.getBean("userService", UserService.class);
    String result = userService.queryUserInfo();
    System.out.println("测试结果:" + result);
    System.out.println("ApplicationContextAware:"+userService.getApplicationContext());
    System.out.println("BeanFactoryAware:"+userService.getBeanFactory());
}
  • The test method is mainly to add a call about the new Aware implementation, and the corresponding log information is also printed for other unnecessary calls, which can be seen in the test results.

test result

执行:init-method
ClassLoader:sun.misc.Launcher$AppClassLoader@14dad5dc
Bean Name is:userService
测试结果:小傅哥,腾讯,深圳
ApplicationContextAware:cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext@5ba23b66
BeanFactoryAware:cn.bugstack.springframework.beans.factory.support.DefaultListableBeanFactory@2ff4f00f
执行:destroy-method



Process finished with exit code 0
  • It can be seen from the test results that the specific implementations (BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware) corresponding to the newly added awareness interfaces in this chapter can already output the results as expected.

Six, summary

  • In the current implementation of the Spring framework, certain functional points have become more and more complete, especially the life cycle of the Bean object, which has many manifestations. The overall summary is shown in Figure 9-3

    图 9-3

  • In this chapter, the implementation of the four inherited interfaces BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, and BeanFactoryAware of the awareness interface of Aware extends the functions of Spring. If you have done the development of Spring middleware, you will definitely use these classes. Now you have not only used them, but you also know when they were reached. You can check the instantiation order of the classes in the future. There is a clear idea.
  • The realization of the content of each chapter is to fill in the functions of the various modules on the structure with the design pattern as the core. It is not much to gain from simply writing the code. It is necessary to understand why the design is so designed and the benefits of such a design. What is it, how to use so many interfaces and abstract classes, these are the core of Spring framework learning.

Seven, series recommendation


小傅哥
4.7k 声望28.4k 粉丝

CodeGuide | 程序员编码指南 - 原创文章、案例源码、资料书籍、简历模版等下载。