这章咱们来实现FactoryBean,是FactoryBean不是BeanFactory啊,话说,是有多敬业多好的产品,有了BeanFactory还想出来了FactoryBean,
BeanFactory是将将某个类注册到bean容器工厂里
FactoryBean也是一样的功能,唯一不同的是通过实现ioc提供的一个接口,我们系统或者我们自己的类实现此接口,可以做一些自己想要的功能然后返回给IOC容器里的操作
首先我们这次要添加两个类,一个是FactoryBean,用来让用户进行实现的接口,第二个是要添加一个FactoryBeanRegistrySupport类,专门用来处理Factory的支持类FactoryBean注册获取等操作,还要修改一个类,修改下AbstractBeanFactory类文件,将如果是FactoryBean实现类就反馈,不是就走BeanFactory那一套操作。那接下来就上代码把
1.代码实现
1.创建FactoryBean接口,提供3个方法,获取对象、对象类型,以及是否是单例对象,如果是单例对象依然会被放到内存中
package com.spring.sourcecode.springframework.beans.factory;
/**
* @Author df
* @Date 2022/4/30 10:54
* @Version 1.0
*/
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
2.主要处理的就是关于 FactoryBean 此类对象的注册操作,也定义了缓存操作 factoryBeanObjectCache,用于存放单例类型的对象,避免重复创建,整体的核心逻辑就是注册获取。
package com.spring.sourcecode.springframework.beans.factory.support;
import com.spring.sourcecode.springframework.beans.BeansException;
import com.spring.sourcecode.springframework.beans.factory.FactoryBean;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author df
* @Date 2022/4/30 11:31
* @Version 1.0
*/
public class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();
// 从容器里取出数据
protected Object getCachedObjectForFactoryBean(String beanName) {
Object object = this.factoryBeanObjectCache.get(beanName);
return (object != NULL_OBJECT ? object : null);
}
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {
if (factory.isSingleton()) {
// 是单例从容器中取出来
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 容器中取不到从factory实现类里去获取
object = doGetObjectFromFactoryBean(factory, beanName);
this.factoryBeanObjectCache.put(beanName, object != null ? object : NULL_OBJECT);
}
return (object != NULL_OBJECT ? object : null);
} else {
return doGetObjectFromFactoryBean(factory, beanName);
}
}
// 从FactoryBean实现类里获取对象
private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName) {
try {
return factory.getObject();
} catch (Exception e) {
throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
}
}
}
3.修改AbstractBeanFactory类,主要是更改doGetBean方法里返回bean的方式,通过getObjectForBeanInstance()添加此方法用来区分是正常bean还是FactoryBean,此类就使用了FactoryBeanRegistrySupport,所以需要在继承类里修改下继承FactoryBeanRegistrySupport就可以了
protected <T> T doGetBean(final String name, final Object[] args) {
// 获取单例bean
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
return (T) getObjectForBeanInstance(sharedInstance, name);
}
BeanDefinition beanDefination = getBeanDefinition(name);
Object bean = createBean(name, beanDefination, args);
return (T) getObjectForBeanInstance(bean, name);
}
private 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;
}
2.测试准备
添加IUserDao,
public interface IUserDao {
String queryUserName(String uId);
}
添加UserService,userService里使用了IUserDao
package com.spring.sourcecode.springframework.test;
import com.spring.sourcecode.springframework.beans.factory.*;
import com.spring.sourcecode.springframework.context.ApplicationContext;
import com.spring.sourcecode.springframework.context.ApplicationContextAware;
/**
* @Author df
* @Date 2021/11/8 10:14
* @Version 1.0
*/
public class UserService {
private String uId;
private String company;
private IUserDao userDao;
private String location;
public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
添加了实现了FactoryBean的ProxyBeanFactory类,就可以做我们自己用户该做的事情了
package com.spring.sourcecode.springframework.bean;
import com.spring.sourcecode.springframework.beans.factory.FactoryBean;
import com.spring.sourcecode.springframework.test.IUserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
/**
* @Author df
* @Date 2022/4/30 14:26
* @Version 1.0
*/
public class ProxyBeanFactory implements FactoryBean<IUserDao> {
@Override
public IUserDao getObject() throws Exception {
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;
}
}
3.测试
单元测试
public class ApiTest {
//
@Test
public void testFactoryBean() {
// 1.初始化BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
// 2.获取bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
System.out.println("测试结果:" + userService.queryUserInfo());
}
}
执行完成,FactoryBean接口测试完成