- 1. 概念
- 2. FactoryBean的作用
- 3. 通过代码查看FactoryBean的作用
- 4. 根据源码上解析
- 1. 先说结论
- 2. 源码分析
- 5. FactoryBean运用在什么场景下
- 6. @Bean跟FactoryBean的区别
- 7. FactoryBean中的创建Bean对象相当于懒加载?
- 8. BeanFactory与FactoryBean的区别
- 9. 如何拿到实现FactoryBean的类的bean对象,而不是getObject的bean对象
-
FactoryBean 本质上是一个接口,具体如下:
public interface FactoryBean
{ // 获取一个对象 @Nullable T getObject() throws Exception; // 获取对象的类型 @Nullable Class> getObjectType(); // 判断是否为单例,默认返回true 即是单例 default boolean isSingleton() { return true; } }
- 实现它的bean类实际上是一个特殊的bean,允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean
-
通过下面测试代码,看到FactoryBean的本质:
定义一个bean类,并getBean
@Component public class UserService { }
public class demo { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.king.learning"); System.out.println(applicationContext.getBean("userService")); } }
上面是我们常用的方式,确实得到的是UserService对象。
现在将UserService 实现 FactoryBean接口,并重新运行getBean。public class User { // 注意 User 上没有任何注解 } @Component public class UserService implements FactoryBean{ @Override public Object getObject() throws Exception { // 创建user对象 return new User(); } @Override public Class> getObjectType() { // 返回 User.class return User.class; } }
// 测试代码不变 public class demo { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.king.learning"); // 留意:我仍然是getBean("userService") System.out.println(applicationContext.getBean("userService")); } }
通过上面结论:- 即使我们getBean(“userService”)但是返回的居然是User对象。
- FactoryBean允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean
- spring容器在启动的时候,会去扫描带注解的类,生成对应的BeanDefinition,并生成对应的Bean对象,然后放入单例池中,注意:这里生成的bean 是非懒加载的单例bean。
- 在getBean的时候,会去判断 这个bean对象是否实现了FactoryBean接口?
- 如果实现则不返回这个bean对象,而是去判断isSingleton是否为单例?
- 如果不是单例的,直接调用getObject方法生成新的对象并返回。
- 如果是单例的,则取缓存factoryBeanObjectCache (factorybean 产生的对象 的缓存),
- 如果是单例的且不在缓存中,则会去调用factoryBean的getObject方法,并将生成的对象放入在缓存中,并返回。
- 注意:getObject方法只会被调用一次,因为第一次创建之后,都会存在缓存factoryBeanObjectCache 中,不会在getObejct了
由于spring的getBean方法里面做了很多事情,因此这篇文章只看跟factoryBean有关系的源码
到这里基本上FactoryBean的大体有一定的理解,也知道怎么调用的,但是我们似乎只是理解,好像还差点什么东西,别急,精彩还在下面。
5. FactoryBean运用在什么场景下-
我们知道FactoryBean的作用:允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean。
-
举例:使用mybatis的时候,我们定义的Dao层都是接口,但是在spring容器中确实是存在对应的bean对象,就是用了FactoryBean,当然mybatis使用的是MapperFactoryBean。
-
简单模拟:
// 定义dao接口 public interface UserDao { String getAll(); } // 定义FactoryBean @Component public class UserDaoFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { // 这里使用了 动态代理 return Proxy.newProxyInstance(UserDaoFactoryBean.class.getClassLoader(), new Class[]{UserDao.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }); } @Override public Class> getObjectType() { return UserDao.class; } } // 定义Service,并依赖注入dao接口 @Component public class UserService{ @Autowired private UserDao userDao; } // 测试代码 public class demo { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.king.learning"); final UserService userService = applicationContext.getBean("userService", UserService.class); System.out.println(userService); } }
从结论可以看出,没有报错,可以注入,且注入的是个代理对象。 -
相关知识链接:
- 动态代理:https://blog.csdn.net/xueyijin/article/details/122276921
- mybatis的Mapper创建bean对象并放入spring容器:期待,小编努力中。
- @Bean的作用:也是创建一个对象,并放入spring容器中,似乎跟FactoryBean没有什么区别。
- 实际上:FactoryBean的功能是比@Bean强的,@Bean是一个注解,FactoryBean是一个接口,类去实现它,可以额外拥有很多功能。
- 如:
- 是的,相当于懒加载,根据查看getBean 有关于FactoryBean的源码,我们可以知道,在getBean的时候,才会去判断该对象是不是FactoryBean,如果是且第一次获取,则会先去调用 Factorybean的getObject方法,先创建对象,因此是懒加载。
- BeanFactory是容器,是大型工厂,可以产生各种各样类型的bean,其中包括普通bean,也有FactoryBean。
- FactoryBean也是工厂,但是是小型工厂,可以产生同一种类型的bean。
-
只需要在getBean的时候,在beanName前面加上 & 符号,这是spring的规定。
-
getBean("&userService") 加上& 则会拿到factoryBean自身的对象了,而不是getObject的bean对象。
-
源码解析:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)