文章目录
前言
我们在之前的文章中实现了spring框架中大部分的功能,到本章为止我们的框架开始逐渐强大。但是这么强大的框架功能都是属于他自己的,我们如何可以如果要获取框架的某一部分能力该怎么做呢?
需求分析
日常开发中,我们可以配置xml完成依赖注入,但是这个bean在开发中我们需要做调整,总不能再通过配置修改bean吧?所以,我们有没有办法在项目运行过程中操作容器对bean容器进行相关的操作呢?
实现思路
解决方案概述
通过阅读spring的源码,我们发现spring框架对这种需求的解决方案很有技巧性,既然需要框架的能力,那么我们就定义一个接口Aware
,假如用户需要beanFactory的能力,那么我们就定义一个BeanFactoryAware
接口继承Aware
,暴露一个setBeanFactory
方法。假如用户需要ClassLoader
的能力,那么我们就定义一个BeanClassLoaderAware
接口继承Aware
,暴露一个setBeanClassLoaderAware
方法。
然后在实现bean初始化过场中,我们在代码中判断,如果这个bean是是否属于Aware
,若属于我们就去判断他继承了那些Aware
,例如实现了BeanFactoryAware
,那么我就值bean初始化的时候调用这个bean的setBeanFactory
将bean容器交由这个bean进行自己所需要的处理。
类图
类图如下所示,可以看出spring在对bean初始化的时候
可以看出spring在bean初始化的时候有对bean进行相应判断,属于那种Aware
就set那种Aware
的能力,需要注意一下一个特殊情况,ApplicationContext
是spring自己的bean,并不能被我们所控制,所以我们必须在ApplicationContext
的实现refresh
让他通过ApplicationContextAwareProcessor
把自己传给需要它的对象。
相关代码
Aware
package cn.shark.springframework.beans.factory;
/**
* 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 {
}
BeanClassLoaderAware
package cn.shark.springframework.beans.factory;
public interface BeanClassLoaderAware {
void setBeanClassLoader(ClassLoader classLoader);
}
BeanNameAware
package cn.shark.springframework.beans.factory;
public interface BeanNameAware extends Aware {
void setBeanName(String name);
}
BeanFactoryAware
package cn.shark.springframework.beans.factory;
import cn.shark.springframework.beans.BeansException;
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
ApplicationContextAware
package cn.shark.springframework.beans.factory;
import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.context.ApplicationContext;
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
AbstractAutowireCapableBeanFactory
package cn.shark.springframework.beans.factory.support;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.PropertyValue;
import cn.shark.springframework.beans.PropertyValues;
import cn.shark.springframework.beans.factory.*;
import cn.shark.springframework.beans.factory.config.AutowireCapableBeanFactory;
import cn.shark.springframework.beans.factory.config.BeanDefinition;
import cn.shark.springframework.beans.factory.config.BeanPostProcessor;
import cn.shark.springframework.beans.factory.config.BeanReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* AutowireCapableBeanFactory 前后置处理器操作
* AbstractBeanFactory 前后置处理器操作
*/
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(beanName, beanDefinition, args);
applyPropertyValues(beanName, bean, beanDefinition);
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
addSingleton(beanName, bean);
return bean;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
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);
}
}
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
try {
invokeInitMethods(beanName, wrappedBean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
}
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName)) {
Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor<?> ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanName, beanDefinition, constructorToUse, args);
}
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
for (PropertyValue pv : beanDefinition.getPropertyValues().getPropertyValues()) {
String name = pv.getName();
Object value = pv.getValue();
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
@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;
}
}
AbstractApplicationContext
package cn.shark.springframework.context.support;
import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.ConfigurableListableBeanFactory;
import cn.shark.springframework.beans.factory.config.BeanFactoryPostProcessor;
import cn.shark.springframework.beans.factory.config.BeanPostProcessor;
import cn.shark.springframework.beans.factory.core.io.DefaultResourceLoader;
import cn.shark.springframework.context.ConfigurableApplicationContext;
import java.util.Map;
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
/**
* 刷新容器
*
* @throws BeansException
*/
@Override
public void refresh() throws BeansException {
// 1. 创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
invokeBeanFactoryPostProcessors(beanFactory);
// 4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessors(beanFactory);
// 5. 提前实例化单例Bean对象
beanFactory.preInstantiateSingletons();
}
protected abstract void refreshBeanFactory() throws BeansException;
protected abstract ConfigurableListableBeanFactory getBeanFactory();
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
/**
* 按照类型返回bean实例
*
* @param type
* @return
* @throws BeansException
*/
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
/**
* 返回注册表中所有的bean名称
*
* @return
*/
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... agrs) throws BeansException {
return getBeanFactory().getBean(name, agrs);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override
public void close() {
getBeanFactory().destroySingletons();
}
}
测试
配置
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="cn.shark.springframework.bean.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/>
<bean id="userService" class="cn.shark.springframework.bean.UserService">
<property name="uId" value="10001"/>
<property name="company" value="腾讯"/>
<property name="location" value="深圳"/>
<property name="userDao" ref="userDao"/>
</bean>
<bean class="cn.shark.springframework.common.MyBeanFactoryPostProcessor"/>
<bean class="cn.shark.springframework.common.MyBeanPostProcessor"/>
</beans>
userDao
package cn.shark.springframework.bean;
import java.util.HashMap;
import java.util.Map;
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);
}
}
userService
package cn.shark.springframework.bean;
import cn.shark.springframework.beans.BeansException;
import cn.shark.springframework.beans.factory.*;
import cn.shark.springframework.context.ApplicationContext;
/**
* 测试bean
*
* @author Zsy
* @date 2021-08-30 21:41
*/
public class UserService implements InitializingBean, DisposableBean, BeanFactoryAware, BeanClassLoaderAware, BeanNameAware, ApplicationContextAware {
private String uId;
private String company;
private String location;
private UserDao userDao;
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
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;
}
@Override
public void destroy() throws Exception {
System.out.println("执行:UserService.destroy");
}
/**
* bean处理了属性填充后调用
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行:UserService.afterPropertiesSet");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("setBeanClassLoader");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
System.out.println("setBeanName");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
测试代码
@Test
public void test_Processor(){
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println(result);
System.out.println(userService.getApplicationContext());
UserDao userDao = (UserDao) userService.getBeanFactory().getBean("userDao");
String name = userDao.queryUserName("10001");
System.out.println("name:"+name);
}
输出结果
执行:init-method
setBeanClassLoader
setBeanName
执行:UserService.afterPropertiesSet
巨大情,改为:测试公司,改为:福建省
cn.shark.springframework.context.support.ClassPathXmlApplicationContext@7cf10a6f
name:巨大情
执行:UserService.destroy
执行:destroy-method