掌握Spring中的beanfactory与factorybean有什么好处?

      版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。          https://blog.youkuaiyun.com/weixin_43277643/article/details/83273161        </div>
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
                          <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
      <div class="htmledit_views" id="content_views">
        <h2><a name="t0"></a>前言</h2>

  如果说Spring最核心的东西是什么,那就非Beans组件莫属了,Bean对于Spring的意义就象OOP对于Java的意义一样。

  今天要讲的是Spring中的 BeanFactory与FactoryBean的区别以及具体使用。

1. BeanFactory

  BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

  Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

实例化容器


 
 
  1. 1 Resource resource = new FileSystemResource( "beans.xml");
  2. 2 BeanFactory factory = new XmlBeanFactory(resource);

 
 
  1. 1 ClassPathResource resource = new ClassPathResource( "beans.xml");
  2. 2 BeanFactory factory = new XmlBeanFactory(resource);

 
 
  1. 1 ApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "applicationContext.xml", "applicationContext-part2.xml"});
  2. 3 BeanFactory factory = (BeanFactory) context;

  基本就是这些了,接着使用getBean(String beanName)方法就可以取得bean的实例;BeanFactory提供的方法及其简单,仅提供了六种方法供客户调用:

  • boolean containsBean(String beanName) 判断工厂中是否包含给定名称的bean定义,若有则返回true

  • Object getBean(String) 返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常

  • Object getBean(String, Class) 返回以给定名称注册的bean实例,并转换为给定class类型

  • Class getType(String name) 返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常

  • boolean isSingleton(String) 判断给定名称的bean定义是否为单例模式

  • String[] getAliases(String name) 返回给定bean名称的所有别名

2. FactoryBean

  以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

  例如自己实现一个FactoryBean,功能:用来代理一个对象,对该对象的所有方法做一个拦截,在调用前后都输出一行LOG,模仿ProxyFactoryBean的功能。


 
 
  1. /**
  2. * my factory bean<p>
  3. * 代理一个类,拦截该类的所有方法,在方法的调用前后进行日志的输出
  4. *
  5. */
  6. public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {
  7. private static final Logger logger = LoggerFactory.getLogger(MyFactoryBean.class);
  8. private String interfaceName;
  9. private Object target;
  10. private Object proxyObj;
  11. @Override
  12. public void destroy() throws Exception {
  13. logger.debug( "destroy......");
  14. }
  15. @Override
  16. public void afterPropertiesSet() throws Exception {
  17. proxyObj = Proxy.newProxyInstance(
  18. this.getClass().getClassLoader(),
  19. new Class[] { Class.forName(interfaceName) },
  20. new InvocationHandler() {
  21. @Override
  22. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  23. logger.debug( "invoke method......" + method.getName());
  24. logger.debug( "invoke method before......" + System.currentTimeMillis());
  25. Object result = method.invoke(target, args);
  26. logger.debug( "invoke method after......" + System.currentTimeMillis());
  27. return result;
  28. }
  29. });
  30. logger.debug( "afterPropertiesSet......");
  31. }
  32. @Override
  33. public Object getObject() throws Exception {
  34. logger.debug( "getObject......");
  35. return proxyObj;
  36. }
  37. @Override
  38. public Class<?> getObjectType() {
  39. return proxyObj == null ? Object.class : proxyObj.getClass();
  40. }
  41. @Override
  42. public boolean isSingleton() {
  43. return true;
  44. }
  45. public String getInterfaceName() {
  46. return interfaceName;
  47. }
  48. public void setInterfaceName(String interfaceName) {
  49. this.interfaceName = interfaceName;
  50. }
  51. public Object getTarget() {
  52. return target;
  53. }
  54. public void setTarget(Object target) {
  55. this.target = target;
  56. }
  57. public Object getProxyObj() {
  58. return proxyObj;
  59. }
  60. public void setProxyObj(Object proxyObj) {
  61. this.proxyObj = proxyObj;
  62. }
  63. }

XML-Bean配置如下


 
 
  1. 1 <bean id= "fbHelloWorldService" class= "com.ebao.xxx.MyFactoryBean">
  2. 2 <property name= "interfaceName" value= "com.ebao.xxx.HelloWorldService" />
  3. 3 <property name= "target" ref= "helloWorldService" />
  4. 4 </bean>

Junit Test class


 
 
  1. @RunWith(JUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = { MyFactoryBeanConfig.class })
  3. public class MyFactoryBeanTest {
  4. @Autowired
  5. private ApplicationContext context;
  6. /**
  7. * 测试验证FactoryBean原理,代理一个servcie在调用其方法的前后,打印日志亦可作其他处理
  8. * 从ApplicationContext中获取自定义的FactoryBean
  9. * context.getBean(String beanName) ---> 最终获取到的Object是FactoryBean.getObejct(),
  10. * 使用Proxy.newInstance生成service的代理类
  11. */
  12. @Test
  13. public void testFactoryBean() {
  14. HelloWorldService helloWorldService = (HelloWorldService) context.getBean( "fbHelloWorldService");
  15. helloWorldService.getBeanName();
  16. helloWorldService.sayHello();
  17. }
  18. }

  其实FactoryBean这种特点,可以实现很多有用的功能。有兴趣的同学不妨了解下。

总结

  Spring总是面试中面试官衷情的知识点,虽说Spring源码看起来在实际工作当中并没有什么特别的用处,但是随着技术经验的不断增长,会发现了解Spring底层原理有多大用处!因此我给大家推荐一个Java架构群:895244712,里面有分布式,微服务,性能优化等技术点底层原理的视频,也有众多想要提升的小伙伴讨论技术,欢迎大家加群一起交流学习。

  了解Spring中的 BeanFactory与FactoryBean不仅可以帮助我们更好地完成工作,还能够使我们对spring的理解更加深入,如果以后面试官问起来,也能做到胸有成竹。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值