手撸Spring10: 通过Bean作用域管理对象, FactoryBean的实现及使用

交给Spring 管理的 Bean对象,获取的就是一定是单例模式吗? 有没有可能是原型模式呢?

其实我们在配置参数时默认走的就是单例模式, 但特殊情况下需要原型模式也是可以调整的嘛!

BeanDefinition

既然要调整Bean的信息,那肯定要先改造bean定义类咯!

package com.linnine.spring.beans.factory.config;

import com.linnine.spring.beans.PropertyValues;
import lombok.Data;

@Data
public class BeanDefinition {

    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    private Class beanClass;

    //补充属性
    private PropertyValues propertyValues;

    //初始化
    private String initMethodName;

    //销毁
    private String destroyMethodName;

    //10 新增作用于
    private String scope = SCOPE_SINGLETON;

    private boolean singleton = true;

    private boolean prototype = false;

    //这里升级为只传类型,而不是实例 在需要的时候才去实例化
    public BeanDefinition(Class beanClass){
        this.beanClass=beanClass;
        //如果没有就传个空的 避免后去捞的时候空指针异常
        this.propertyValues=new PropertyValues();
    }

    public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
        this.beanClass = beanClass;
        this.propertyValues = propertyValues;
    }

    public boolean isSingleton(){
        return SCOPE_SINGLETON.equals(scope);
    }
}

ConfigurableBeanFactory

加一下那两条属性
package com.linnine.spring.beans.factory.config;

//09 改成接口 实现BeanFactory
public interface ConfigurableBeanFactory extends BeanFactory {
    //10 添加两条常量
    String SCOPE_SINGLETON = "singleton";
    String SCOPE_PROTOTYPE = "prototype";

    //09 添加一个接口方法
    void addBeanPostProcessor(BeanPostProcessor var1);

}

XmlBeanDefinitionReader

既然是添加了这些信息,那就要去添加, 主要还是从配置文件里面添加,所以还是去修改读取配置类

package com.linnine.spring.beans.factory.xml;

其实就改了几行

在这里插入图片描述

AbstractAutowireCapableBeanFactory

既然配置了单例信息,在获取bean的时候就要判断了!

之前有个默认就添加到单例bean管理了,现在要先判断了.
在这里插入图片描述
另外还要判断是否需要销毁


开始对单例Bean进行管理调整

FactoryBean

我们提供一个口子,供外部实现

package com.linnine.spring.beans.factory;

public interface FactoryBean<T> {

    /**
     * 获取对象
     * @return
     * @throws Exception
     */
    T getObject() throws Exception;

    /**
     * 对象类型
     * @return
     */
    Class<?> getObjectType();

    /**
     * 是否是单例对象
     * @return
     */
    boolean isSingleton();
}

FactoryBeanRegistrySupport

扩展对单例Bean的管理
package com.linnine.spring.beans.factory.support;

/**
 * 10新增 扩展对单例Bean的管理
 */
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

    /**
     * 单例bean缓存
     */
    private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();

    /**
     * 直接获取
     * @param beanName
     * @return
     */
    protected Object getCachedObjectForFactoryBean(String beanName) {
        return this.factoryBeanObjectCache.get(beanName);
    }

    protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {
        //如果是单例模式
        if (factory.isSingleton()){
            //先去缓存中取看看有没有
            Object object = this.factoryBeanObjectCache.get(beanName);
            //没有
            if (object == null){
                //新建
                object = doGetObjectFromFactoryBean(factory,beanName);
                //塞入缓存
                this.factoryBeanObjectCache.put(beanName,object);
            }
            return object;
        }else {
            //原型模式直接创建
            return doGetObjectFromFactoryBean(factory,beanName);
        }
    }

    private Object doGetObjectFromFactoryBean(FactoryBean factory, String beanName){
        try {
            return factory.getObject();
        } catch (Exception e) {
            throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
        }
    }
}

AbstractBeanFactory

扩展bean工厂管理

package com.linnine.spring.beans.factory.support;

//09 从实现BeanFactory改成实现ConfigurableBeanFactory
//10 从继承DefaultSingletonBeanRegistry 改成继承 FactoryBeanRegistrySupport(这个新类就是继承自DefaultSingletonBeanRegistry,就等于是再扩展了一些功能)
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    //09新增 管理后处理器 源码的获取不是通过new这个, 这里临时用一下
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    //10 新增
    protected <T> T doGetBean(final String name,final Object[] args){
        Object sharedInstance = getSingleton(name);
        if(sharedInstance != null){
            return (T)  getObjectForBeanInstance(sharedInstance,name);
        }
        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition, args);
        return (T)getObjectForBeanInstance(bean,name);
    }
    //10 新增 通过工厂bean生成
    protected Object getObjectForBeanInstance(Object beanInstance, String beanName){
        //如果不是 直接返回
        if (!(beanInstance instanceof FactoryBean)){
            return beanInstance;
        }
        //如果是 先从缓存中读
        Object object = getCachedObjectForFactoryBean(beanName);

        //如果缓存没有 就通过工厂获取
        if (object == null){
            FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
            object = getObjectFromFactoryBean(factoryBean, beanName);
        }
        return object;

    }

    public Object getBean(String beanName,Object... args){
        //继承自DefaultSingletonBeanRegistry 的方法
        Object bean = getSingleton(beanName);
        if (bean != null){
            return bean;
        }
        //获取不到就两个抽象方法 让实现此类的去做实现
        BeanDefinition beanDefinition = getBeanDefinition(beanName);
        return createBean(beanName,beanDefinition,args);

    }

    protected abstract BeanDefinition getBeanDefinition(String name) throws BeansException;

    //添加参数
    protected abstract Object createBean(String beanName,BeanDefinition bean,Object... args) throws BeansException;

    //09 改造
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }
    //09 转移 原本的获取改成从这里获取
    public BeanPostProcessor[] getBeanPostProcessors(){
        return this.beanPostProcessors.toArray(new BeanPostProcessor[0]);
    }
}

spring已经实现好了,开始外部实现

IUserDao

之前都是直接UserDao实现,限制改成接口,然后通过FactoryBean来实现

package com.linnine.spring.bean.dao;

public interface IUserDao {
    String queryUserName(String uId);
}

ProxyBeanFactory

实现FactoryBean的三个接口,主要是实现获取对象,把之前UserDao的一些工作搬到这里面来

package com.linnine.spring.bean;

import com.linnine.spring.bean.dao.IUserDao;
import com.linnine.spring.beans.factory.FactoryBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class ProxyBeanFactory implements FactoryBean<IUserDao> {

    @Override
    public IUserDao getObject() {
        InvocationHandler handler = (proxy, method, args)->{
            Map<String, String> hashMap = new HashMap<>();
            hashMap.put("10001", "小傅哥");
            hashMap.put("10002", "八杯水");
            hashMap.put("10003", "阿毛");
            return "你被代理了 " + method.getName() + ":" + hashMap.get(args[0].toString());
        };

        return (IUserDao)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{IUserDao.class},handler);
    }

    @Override
    public Class<?> getObjectType() {
        return IUserDao.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

这里要引入一个依赖

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>

UserService

这里属性改成IUserDao 改动不大
在这里插入图片描述

spring.xml

修改配置类,userDao 改成通过工厂类代理生成

顺便把userService配置一个作用域 改成原型模式

<?xml version="1.0" encoding="UTF-8"?>
<beans>

<!--
    <bean id="userDao" class="com.linnine.spring.bean.dao.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/>
-->

    <bean id="proxyUserDao" class="com.linnine.spring.bean.ProxyBeanFactory"/>

    <bean id="userService" class="com.linnine.spring.bean.service.UserService" scope ="prototype">
        <property name="uId" value="10001"/>
        <property name ="company" value="腾讯"/>
        <property name="location" value="深圳"/>
        <property name="userDao" ref="proxyUserDao"/>
    </bean>

<!--    <bean class="com.linnine.spring.common.MyBeanFactoryPostProcessor"/>
    <bean class="com.linnine.spring.common.MyBeanPostProcessor"/>-->
</beans>

开始测试

@Test
public void test_prototype(){
    //初始化
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    applicationContext.registerShutdownHook();

    UserService userService01 = (UserService) applicationContext.getBean("userService", UserService.class);
    UserService userService02 = (UserService) applicationContext.getBean("userService", UserService.class);

    System.out.println(userService01);
    System.out.println(userService02);

    System.out.println(userService01 + " 十六进制哈希:" + Integer.toHexString(userService01.hashCode()));
    System.out.println(ClassLayout.parseInstance(userService01).toPrintable());

}

报错1:

cn.hutool.core.convert.ConvertException: Can not Converter from [com.linnine.spring.bean.ProxyBeanFactory$$EnhancerByCGLIB$$18a2020a] to [com.linnine.spring.bean.dao.IUserDao]

我们获取这个类的时候, 在创建时应该判断是否为Factory才对呀,直接走里面的创建, 而不是让spring来帮我们创建

主要应该是因为我们的doGetBean写了没用到,我看看要再哪里改

看了一下源码,在写完doGetBean以后, 就把getBean内部取代掉了,区别就是重载各种getBean,修改其参数,内部封装调用
在这里插入图片描述
然后我们这里还是简单版的doGetBean, 先简单替换一下.

AbstractBeanFactory

package com.linnine.spring.beans.factory.support;

在这里插入图片描述


报错2

这次是在toString的时候报错了,因为我在UserService上面加了个@Data注解,里面有包含toString 所以把这个注解改成@Getter和@Setter就行了.

结果如下
在这里插入图片描述

可以看到因为是原型模式,所以两个userService不一样,还有可以看到hash值,不过顺序是倒着的

然后是看一下我们的代理测试,运行正常
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值