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
- 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
- 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
- How many lines of code do I need to write to get a development job without spending money on training?
- 90% of programmers do not use too many threads and locks. How do they become architects?
- holds the grass, you even poisoned the code!
- Netty+JavaFx combat: imitating the desktop version of WeChat chat
- The middle stage that had just gone hot was dismantled, and a large wave of companies couldn't put it down or pick it up!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。