文章目录
- 一、目标:Aware感知容器对象
- 二、设计:Aware感知容器对象
- 三、实现:Aware感知容器对象
- 3.1 工程结构
- 3.2 Spring感知接口类图
- 3.3 定义标记接口和容器感知类
- 3.3.1 定义标记接口
- 3.3.2 对象工厂感知接口
- 3.3.3 类加载感知接口
- 3.3.4 对象名称感知接口
- 3.3.5 应用上下文感知接口
- 3.4 包装应用上下文处理器
- 3.4.1 包装应用上下文处理器
- 3.4.2 注册 BeanPostProcessor
- 3.5 感知调用操作
- 3.5.1 抽象对象工厂
- 3.5.2 感知调用操作
- 四、测试:Awrae感知容器对象
- 4.1 修改UserDao用户对象
- 4.2 单元测试
- 五、总结:Aware感知容器对象
一、目标:Aware感知容器对象
💡 如何在获得 Spring 的功能时做些扩展框架的使用该怎么操作?
- 目前实现的 Spring 框架中,在 Bean 操作上提供的能力,包括:
- Bean 对象的定义和注册。
- 操作 Bean 对象过程中执行的
BeanFactoryPostProcessor
、BeanFactoryPostProcessor
、InitializingBean
、DisposableBean
。
- 在 XML 新增的一些配置处理,让我们可以对 Bean 对象有更强的操作性。
- 那么,如果我们想获得 Spring 框架提供的
BeanFactory
、ApplicationContext
、BeanClassLoader
等这些功能做一些扩展框架的使用时该怎么操作呢?- 所以我们希望在 Spring 框架中提供一种能感知容器操作的接口,如果谁实现类这样的接口,就可以获取接口入参中的各类能力。
二、设计:Aware感知容器对象
💡 希望拿到 Spring 框架中一些提供的资源,那么首先需要考虑以一个什么方式去获取,之后定义出来的获取方式,在 Spring 该怎么去承接?
实现了这两项内容,就可以扩展出你需要的一些属于 Spring 框架本身的能力了。
- 在 Bean 对象实例化阶段我们操作过一些额外定义、属性、初始化和销毁的操作,其实如果像获取 Spring 一些如
BeanFactory
、ApplicationContext
时,也可以通过此类方式进行实现。- 需要定义一个标记性的接口,这个接口不需要有方法,它只起到标记作用。
- 而具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过
instanceof
进行判断和调用。
- 定义接口
Aware
,在 Spring 框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。- 也就是通过这个桥梁,向具体的实现类中提供容器服务。
- 继承
Aware
的接口包括:BeanFactoryAware
、BeanClassLoaderAware
、BeanNameAware
、ApplicationContextAware
。 - 在具体的接口实现过程中看到,
- 一部分(
BeanFactoryAware
、BeanClassLoaderAware
、BeanNameAware
)在factory
的support
文件夹下。 - 另外(
ApplicationContextAware
)是在context
的support
中。
- 一部分(
- 这是因为不同的内容获取需要在不同的包下提供。所以:
- 在
AbstractApplicationContext
的具体实现中会用到向beanFactory
添加BeanPostProcessor
内容的ApplicationContextAwareProcessor
操作。 - 最后由
AbstractAutowireCapableBeanFactory
创建createBean
时处理相应的调用操作。
- 在
三、实现:Aware感知容器对象
3.1 工程结构
spring-step-08
|-src|-main| |-java| |-com.lino.springframework| |-beans| | |-factory| | | |-config| | | | |-AutowireCapableBeanFactory.java| | | | |-BeanDefinition.java| | | | |-BeanFactoryPostProcessor.java| | | | |-BeanPostProcessor.java| | | | |-BeanReference.java| | | | |-ConfigurableBeanFactory.java| | | | |-SingletonBeanRegistry.java| | | |-support| | | | |-AbstractAutowireCapableBeanFactory.java| | | | |-AbstractBeabDefinitionReader.java| | | | |-AbstractBeabFactory.java| | | | |-BeabDefinitionReader.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| | | |-HierarcgicalBeanFactory.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| |-util| | |-ClassUtils.java|-test|-java|-com.lino.springframework.test|-bean| |-UserDao.java| |-UserService.java|-ApiTest.java|-resources|-spring.xml
3.2 Spring感知接口类图
- 整个类关系就是关于
Aware
感知的定义和对容器感知的实现。 Aware
有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。- 另外由于
ApplicationContext
并不是在AbstractAutowireCapableBeanFactory
中createBean
方法下的内容。- 所以需要像容器中注册
addBeanPostProcessor
,再由createBean
统一调用applyBeanPostProcessorBeforeInitialization
时进行操作。
- 所以需要像容器中注册
3.3 定义标记接口和容器感知类
3.3.1 定义标记接口
Aware.java
package com.lino.springframework.beans.factory;/*** @description: 标记类接口,实现该接口可以被Spring容器感知*/
public interface Aware {
}
- 在 Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有
instanceof
一起判断使用。
3.3.2 对象工厂感知接口
BeanFactoryAware.java
package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;/*** @description: 实现此接口,即能感知到所属的 BeanFactory*/
public interface BeanFactoryAware extends Aware {/*** 设置对象工厂** @param beanFactory 对象工厂* @throws BeansException 异常*/void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
- 实现此接口,即能感知到所属的 BeanFactory。
3.3.3 类加载感知接口
BeanClassLoaderAware.java
package com.lino.springframework.beans.factory;/*** @description: 实现此接口,即能感知到所属的 ClassLoader*/
public interface BeanClassLoaderAware extends Aware {/*** 设置类加载器** @param classLoader 类加载器*/void setBeanClassLoader(ClassLoader classLoader);
}
- 实现此接口,即能感知到所属的 ClassLoader。
3.3.4 对象名称感知接口
BeanNameAware.java
package com.lino.springframework.beans.factory;/*** @description: 实现此接口,即能感知到所属的 BeanName*/
public interface BeanNameAware {/*** 设置对象名称** @param name 对象名称*/void setBeanName(String name);
}
- 实现此接口,即能感知到所属的 BeanName。
3.3.5 应用上下文感知接口
ApplicationContextAware.java
package com.lino.springframework.context;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.Aware;/*** @description: 实现此接口,即能感知到所属的 ApplicationContext*/
public interface ApplicationContextAware extends Aware {/*** 设置应用上下文** @param applicationContext 应用上下文* @throws BeansException 异常*/void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
- 实现此接口,即能感知到所属的 ApplicationContext。
3.4 包装应用上下文处理器
3.4.1 包装应用上下文处理器
ApplicationContextAwareProcessor.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ApplicationContext;
import com.lino.springframework.context.ApplicationContextAware;/*** @description: 通过 BeanPostProcessor 实现类感知应用上下文对象*/
public class ApplicationContextAwareProcessor implements BeanPostProcessor {private final ApplicationContext applicationContext;public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(applicationContext);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
- 由于
ApplicationContext
的获取并不能直接在创建 Bean 时候就可以拿到,所以需要在refresh
操作时,把ApplicationContext
写入到一个包装的BeanPostProcessor
中去,再由AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization
方法调用。
3.4.2 注册 BeanPostProcessor
AbstractApplicationContext.java
package com.lino.springframework.context.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.context.ConfigurableApplicationContext;
import com.lino.springframework.core.io.DefaultResourceLoader;
import java.util.Map;/*** @description: 抽象应用上下文*/
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {@Overridepublic void refresh() throws BeansException {// 1.创建 BeanFactory,并加载 BeanDefinitionrefreshBeanFactory();// 2.获取 BeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();// 3.添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContextbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 4.在 Bean 实例化之前,执行 BeanFactoryPostProcessinvokeBeanFactoryPostProcessor(beanFactory);// 5.BeanPostProcessor 需要提前与其他 Bean 对象实例化之前执行注册操作registerBeanPostProcessor(beanFactory);// 6.提前实例化单例 Bean 对象beanFactory.preInstantiateSingletons();}...
}
refresh()
方法就是整个 Spring 容器的操作过程,这次新增加了addBeanPostProcessor
操作。- 添加
ApplicationContextAwareProcessor
,让继承自ApplicationContextAware
的 Bean 对象都能感知所属的ApplicationContext
。
3.5 感知调用操作
3.5.1 抽象对象工厂
AbstractBeanFactory.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.util.ClassUtils;
import java.util.ArrayList;
import java.util.List;/*** @description: 抽象的 Bean 工厂基类,定义模板方法*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();...public ClassLoader getBeanClassLoader() {return this.beanClassLoader;}
}
- 添加
ClassLoader
对像,并提供一个获取对象类加载器的方法。getBeanClassLoader()
。
3.5.2 感知调用操作
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.BeanReference;import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** @description: 实现默认bean创建的抽象bean工厂超类* @author: lingjian* @createDate: 2022/11/22 14:39*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();...private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {// invokeAwareMethodsif (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(wrappedBean, beanName);return wrappedBean;}...
}
- 首先在
initializeBean
中,通过判断bean instanceof Aware
,调用三个接口方法。这样就能通知到已经实现了此接口的类。((BeanFactoryAware) bean).setBeanFactory(this)
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader())
((BeanNameAware) bean).setBeanName(beanName)
- 另外还向
BeanPostProcessor
中添加了ApplicationContextAwareProcessor
,此时在这个方法中也会被调用到具体的类实现,得到一个ApplicationContext
属性。
四、测试:Awrae感知容器对象
4.1 修改UserDao用户对象
UserService.java
package com.lino.springframework.test.bean;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.context.ApplicationContext;
import com.lino.springframework.context.ApplicationContextAware;/*** @description: 模拟用户 Bean 对象*/
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;@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("ClassLoader: " + classLoader);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}@Overridepublic void setBeanName(String name) {System.out.println("Bean Name is: " + name);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** 查询用户信息*/public String queryUserInfo() {return userDao.queryUserName(uId) + "," + company + "," + location;}public String getuId() {return uId;}public void setuId(String uId) {this.uId = uId;}public String getCompany() {return company;}public void setCompany(String company) {this.company = company;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}public ApplicationContext getApplicationContext() {return applicationContext;}public BeanFactory getBeanFactory() {return beanFactory;}
}
- 新增加
BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware
四个感知的实现类,并在类中的实现相应的接口方法。
4.2 单元测试
ApiTest.java
@Test
public void test_xml() {// 1.初始化 BeanFactoryClassPathXmlApplicationContext 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());
}
- 测试方法中添加了一写关于新增 Aware 实现的调用,其他不需要调用的也打印了相应的日志信息,可以在测试结果中看到。
测试结果
执行:init-method
ClassLoader: sun.misc.Launcher$AppClassLoader@18b4aac2
Bean Name is: userService
测试结果:张三,阿里,杭州
ApplicationContextAware: com.lino.springframework.context.support.ClassPathXmlApplicationContext@56cbfb61
BeanFactoryAware: com.lino.springframework.beans.factory.support.DefaultListableBeanFactory@1134affc
执行:destroy-method
- 从测试结果来看,新增加的感知接口对应的具体实现(
BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware
),已经可以正常输出结果。
五、总结:Aware感知容器对象
- 本节关于
Aware
的感知接口的四个继承接口BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware
的实现,又扩展了 Spring 的功能。 - 目前关于 Spring 框架的实现中,功能已经越来越趋向于完整,尤其对于 Bean 对象的生命周期。