交给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值,不过顺序是倒着的
然后是看一下我们的代理测试,运行正常