定义Scope注解通过Scope这个注解来标明是单例bean还是多例bean 。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Scope { String value() default "";}定义BeanDefinition在spring中,不会在获取bean的时候再去解析是否为单例,而是通过BeanDefinition类来操作 。对bean的定义,记录了bean类和作用域 。
public class BeanDefinition { private Class type; private String scope; // 单例多例 public Class getType() { return type; } public void setType(Class type) { this.type = type; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; }}因为我们注入spring的bean对象是有Component注解,因此在扫描的时候,我们会通过这个获得到bean,在这时候去创建BeanDefinition对象 。通过判断注解上的值来赋值其作用域,如果没有设置,就默认是单例模式 。创建好的bean对象,我们还需要将他进行保存起来,这个就需要定义ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();存储beanDefinition 。key是component的值,如果component没有传入beanName的值,那就使用spring的命名规则,采用类名首字母小写 。
// 1.7 在通过这个clazz(类)来判断是否有component注解,有则是beanif (clazz.isAnnotationPresent(Component.class)) { Component annotation = clazz.getAnnotation(Component.class); String beanName = annotation.value(); // * 默认生成bean,如果只使用Component注解,没有写上beanName的值,那么就需要自动生成 if (beanName.equals("")) { // 默认开头小字母 beanName = Introspector.decapitalize(clazz.getSimpleName()); } /** * 這就是一个bean了 * 然而在这里并不是直接就创建bean了,bean分为了单例bean和多例bean */ BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setType(clazz); if (clazz.isAnnotationPresent(Scope.class)) { // 判断是单例还是多例Scope scope = clazz.getAnnotation(Scope.class);beanDefinition.setScope(scope.value()); } else {beanDefinition.setScope("singleton"); } beanDefinitionMap.put(beanName, beanDefinition);}getBean底层通过传来一个beanName,通过beanDefinitionMap中获取key为beanName的BeanDefinition对象,进行判空处理 。这样我们可以通过这个BeanDefinition对象去获取作用域,判断是否为单例 。
获取bean在此,我们创建单例的时候,是需要将单例保存起来的,需要定义ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();单例池来保存单例bean 。然后在getBean的时候,如果是单例bean,就可以先去单例池中寻找,如果没找到,再去创建对象 。而多例模式就需要每次都去创建 。
// 获取bean对象public Object getBean(String beanName) { BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); if (beanDefinition == null) { throw new NullPointerException("找不到bean名字为[" + beanName + "]的bean对象"); } else { // 找到就做相应的操作 String scope = beanDefinition.getScope(); if (scope.equals("singleton")) { // 通过单例池获取 Object bean = singletonObjects.get(beanName); if (bean == null) { // 单例池中如果没有bean,就需要去创建 bean = createBean(beanName, beanDefinition); singletonObjects.put(beanName, bean); } return bean; } else { // 多例的就不需要记录,每次都是通过创建 return createBean(beanName, beanDefinition); } }}
经验总结扩展阅读
- 冰的熔点是多少
- 【ASP.NET Core】MVC控制器的各种自定义:应用程序约定的接口与模型
- 基础版 【网络】内网穿透方案&FRP内网穿透实战
- 金线莲的吃法
- 2023年9月6日是疏通管道吉日吗 2023年9月6日适合疏通管道吗
- 半亩是多少
- 银耳可以泡一晚上再煮吗
- 熊猫便便有什么用
- 清除青苔最有效的方法
- 油是导体还是绝缘体