Spring IoC-扩展Bean
# 一、扩展IoC容器
简易IoC容器实现了两个功能:
- 解析外部资源,将外部资源实例化为BeanDefinition。
- 遍历BeanDefinition集合,反射加载Bean,注册Bean。
现在需要将这个IoC容器进行如下扩展:
- 增加单例 Bean 的接口定义,然后把所有的 Bean 默认为单例模式。
- 预留事件监听的接口,方便后续进一步解耦代码逻辑。
- 扩展 BeanDefinition,添加一些属性,现在它只有 id 和 class 两个属性,我们要进一步地丰富它。
# 二、构建单例Bean
# 1、Bean单例管理接口
Bean单例接口定义
需要一个接口简单对Bean单例进行管理,包括基本的获取、增加、判断是否存在等操作。
public interface SingletonBeanRegistry {
/**
* 注册单例
* @param beanName Bean id
* @param singletonObject Bean对象
*/
void registerSingleton(String beanName, Object singletonObject);
/**
* 获取单例
* @param beanName Bean id
* @return Bean对象
*/
Object getSingleton(String beanName);
/**
* 是否包含某个单例Bean
* @param beanName Bean id
* @return
*/
boolean containsSingleton(String beanName);
/**
* 获取所有单例名称
* @return
*/
String[] getSingletonNames();
}
默认Bean单例接口实现
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
/**
* 存放所有Bean的名称
*/
protected List<String> beanNames = new ArrayList<>();
/**
* Bean单例Map
*/
protected Map<String, Object> singletons = new ConcurrentHashMap<>();
@Override
public void registerSingleton(String beanName, Object singletonObject) {
synchronized (singletons) {
singletons.put(beanName, singletonObject);
beanNames.add(beanName);
}
}
protected void removeSingleton(String beanName) {
synchronized (singletons) {
beanNames.remove(beanName);
singletons.remove(beanName);
}
}
@Override
public Object getSingleton(String beanName) {
return singletons.get(beanName);
}
@Override
public boolean containsSingleton(String beanName) {
return singletons.containsKey(beanName);
}
@Override
public String[] getSingletonNames() {
return (String[]) this.beanNames.toArray();
}
}
beanNames
:存储所有单例Bean的别名。singletons
:存储Bean名称和实现类的映射关系。
# 2、Bean工厂接口
Bean工厂接口定义
public interface BeanFactory {
/**
* 根据Bean名称,获取Bean对象
*
* @param beanName Bean名称
* @return Bean对象
* @throws BeansException Bean自定义异常
*/
Object getBean(String beanName) throws BeansException;
/**
* 是否包含某个Bean
* @param name Bean id
*/
Boolean containsBean(String name);
/**
* 注册单例Bean
* @param beanName Bean id
* @param obj Bean对象
*/
void registerBean(String beanName, Object obj);
}
- 新增一个判断是否包含Bean方法。
- 注册方法变为Bean实体注册。
Bean工厂具体实现
public class SimpleBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);
public SimpleBeanFactory() {
}
public void registerBeanDefinition(BeanDefinition beanDefinition) {
beanDefinitions.put(beanDefinition.getId(), beanDefinition);
}
@Override
public Object getBean(String beanName) throws BeansException {
// 先尝试直接单例获取
Object singleton = getSingleton(beanName);
// 如果没有,开始实例化Bean
if (singleton == null) {
// 获取Bean定义
BeanDefinition beanDefinition = beanDefinitions.get(beanName);
if (beanDefinition == null) {
throw new BeansException("错误Bean id");
}
try {
// 反射实例化Bean
singleton = Class.forName(beanDefinition.getClassName()).newInstance();
// 注册单例Bean
registerSingleton(beanName, singleton);
} catch (Exception e) {
e.printStackTrace();
}
}
return singleton;
}
@Override
public Boolean containsBean(String name) {
return containsSingleton(name);
}
@Override
public void registerBean(String beanName, Object obj) {
registerSingleton(beanName, obj);
}
}
该类中,由BeanFactory
来约束行为,继承DefaultSingletonBeanRegistry
来调用具体方法。
# 3、XML解析优化
XML读取解析
public class XmlBeanDefinitionReader {
SimpleBeanFactory simpleBeanFactory;
/**
* 构造函数
*/
public XmlBeanDefinitionReader(SimpleBeanFactory simpleBeanFactory) {
this.simpleBeanFactory = simpleBeanFactory;
}
/**
* 遍历资源,将资源中的bean对象进行注册
* @param resource 外部资源
*/
public void loadBeanDefinitions(Resource resource) {
while (resource.hasNext()) {
Element element = (Element) resource.next();
String beanID = element.attributeValue("id");
String beanClassName = element.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition(beanID, beanClassName);
simpleBeanFactory.registerBeanDefinition(beanDefinition);
}
}
}
XML上下文
public class ClassPathXmlApplicationContext implements BeanFactory {
SimpleBeanFactory simpleBeanFactory;
public ClassPathXmlApplicationContext(String fileName) {
// 获取资源
Resource resource = new ClassPathXmlResource(fileName);
// 解析资源
SimpleBeanFactory beanFactory = new SimpleBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);
this.simpleBeanFactory = beanFactory;
}
@Override
public Object getBean(String beanName) throws BeansException {
return simpleBeanFactory.getBean(beanName);
}
@Override
public Boolean containsBean(String name) {
return simpleBeanFactory.containsBean(name);
}
@Override
public void registerBean(String beanName, Object obj) {
simpleBeanFactory.registerBean(beanName, obj);
}
}
上述两个类中使用的方法,都是simpleBeanFactory
中的单例操作方法。
# 三、事件监听
构建好单例Bean的相关操作之后,为了监控容器的状态,方便后续使用观察者模式解耦代码提供入库,我们需要引入事件监听。
事件监听
public class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 1L;
public ApplicationEvent(Object arg0) {
super(arg0);
}
}
事件发布
public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}
# 四、扩展BeanDefinition
# 1、BeanDefinition扩展
之前我们所定义的BeanDefinition
比较简单,只有两个属性:id
和className
,现对该类进行扩展如下:
public class BeanDefinition {
/**
* 单例
*/
String SCOPE_SINGLETON = "singleton";
/**
* 原型
*/
String SCOPE_PROTOTYPE = "prototype";
/**
* Bean id
*/
private String id;
/**
* Bean类名
*/
private String className;
/**
* Bean实例化类型(单例 | 原型)
*/
private String scope = SCOPE_SINGLETON;
/**
* 是否在加载时候初始化
*/
private boolean lazyInit = false;
/**
* 记录Bean之间依赖关系
*/
private String[] dependsOn;
/**
* 初始方法声明
*/
private String initMethodName;
private volatile Object beanClass;
}
# 2、BeanDefinition操作
需要一个接口,来对BeanDefinition进行例如存放、移除、获取、判断是否存在等操作:
public interface BeanDefinitionRegistry {
/**
* 注册BeanDefinition
* @param name 别名
* @param beanDefinition BeanDefinition
*/
void registerBeanDefinition(String name, BeanDefinition beanDefinition);
/**
* 删除BeanDefinition
* @param name 别名
*/
void removeBeanDefinition(String name);
/**
* 获取BeanDefinition
* @param name 别名
*/
BeanDefinition getBeanDefinition(String name);
/**
* 是否包含某个BeanDefinition
* @param name 别名
* @return
*/
boolean containsBeanDefinition(String name);
}
# 3、BeanFactory新增接口
public interface BeanFactory {
/**
* 判断是否为单例
* @param name 别名
* @return
*/
boolean isSingleton(String name);
/**
* 判断是否为原型
* @param name 别名
* @return
*/
boolean isPrototype(String name);
Class getType(String name);
}
新增三个方法:
- 判断是否为单例
- 判断是否为原型
- 获取Bean的Class类
# 4、SimpleBeanFactory具体实现
SimpleBeanFactory
类还需要额外实现BeanDefinition
操作,以及BeanFactory
新增的三个接口
public class SimpleBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory, BeanDefinitionRegistry{
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
private List<String> beanDefinitionNames = new ArrayList<>();
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
this.beanDefinitionMap.put(name, beanDefinition);
this.beanDefinitionNames.add(name);
if (!beanDefinition.isLazyInit()) {
try {
getBean(name);
} catch (BeansException e) {
}
}
}
public void removeBeanDefinition(String name) {
this.beanDefinitionMap.remove(name);
this.beanDefinitionNames.remove(name);
this.removeSingleton(name);
}
public BeanDefinition getBeanDefinition(String name) {
return this.beanDefinitionMap.get(name);
}
public boolean containsBeanDefinition(String name) {
return this.beanDefinitionMap.containsKey(name);
}
public boolean isSingleton(String name) {
return this.beanDefinitionMap.get(name).isSingleton();
}
public boolean isPrototype(String name) {
return this.beanDefinitionMap.get(name).isPrototype();
}
public Class<?> getType(String name) {
return this.beanDefinitionMap.get(name).getClass();
}
}
# 参考
上次更新: 2024/06/29, 15:13:44