• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
pinyi
博客园    首页    新随笔    联系   管理    订阅  订阅
Spring教程笔记(3)

getBean()

ApplicationContext接口获取Bean方法简介:

• Object getBean(String name) 根据名称返回一个Bean,客户端需要自己进行类型转换;

• T getBean(String name, Class<T> requiredType) 根据名称和指定的类型返回一个Bean,客户端无需自己进行类型转换,如果类型转换失败,容器抛出异常;

• T getBean(Class<T> requiredType) 根据指定的类型返回一个Bean,客户端无需自己进行类型转换,如果没有或有多于一个Bean存在容器将抛出异常;

• Map<String, T> getBeansOfType(Class<T> type) 根据指定的类型返回一个键值为名字和值为Bean对象的 Map,如果没有Bean对象存在则返回空的Map。

 

IOC容器:

  IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际代表者。

  Spring IoC容器如何知道哪些是它管理的对象呢?这就需要配置文件,Spring IoC容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化及装配。一般使用基于xml配置文件进行配置元数据,而且Spring与配置文件完全解耦的,可以使用其他任何可能的方式进行配置元数据,比如注解、基于java文件的、基于属性文件的配置都可以。

Bean:

  由IoC容器管理的那些组成你应用程序的对象我们就叫它Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。那IoC怎样确定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?这就需要配置元数据,在Spring中由BeanDefinition代表,后边会详细介绍,配置元数据指定如何实例化Bean、如何组装Bean等。

如何工作:

一、准备配置文件:xml 就像前边Hello World配置文件一样,在配置文件中声明Bean定义也就是为Bean配置元数据。

二、由IoC容器进行解析元数据: IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装Bean。

三、实例化IoC容器:由客户端实例化容器,并从实例容器中获得获取需要的Bean。

 

一般项目结构:“src”用于存放java文件;“lib”用于存放jar文件;“resources”用于存放配置文件;

 

public class HelloTest {  
       @Test  //jUnit
       public void testHelloWorld() {  
             //1、读取配置文件实例化一个IoC容器  
             ApplicationContext context = new ClassPathXmlApplicationContext("helloworld.xml");  
             //2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”,hello是bean id  
             HelloApi helloApi = context.getBean("hello", HelloApi.class);  
             //3、执行业务逻辑  
             helloApi.sayHello();  
       }  
}  

  在Spring Ioc容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。

容器实现一览:

• XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,可以从classpath或文件系统等获取资源;

  (1)  File file = new File("fileSystemConfig.xml");

           Resource resource = new FileSystemResource(file);

           BeanFactory beanFactory = new XmlBeanFactory(resource);

  (2)Resource resource = new ClassPathResource("classpath.xml");                 

          BeanFactory beanFactory = new XmlBeanFactory(resource);

 • ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件;

         BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");

• FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件。

         BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");

 

小结:

  除了测试程序的代码外,也就是程序入口,所有代码都没有出现Spring任何组件,而且所有我们写的代码没有实现框架拥有的接口,因而能非常容易的替换掉Spring,非入侵。

  客户端代码完全面向接口编程,无需知道实现类,可以通过修改配置文件来更换接口实现,客户端代码不需要任何修改。低耦合。

  如果在开发初期没有真正的实现,我们可以模拟一个实现来测试,不耦合代码,很方便测试。

  Bean之间几乎没有依赖关系,很容易重用。

 

Bean配置相关:

Bean命名:

1. xml里面bean不写id 只写class  对应default-autowire=byType,客户端必须通过接口“T getBean(Class<T> requiredType)”获取Bean;

<bean class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/> 

@Test  
public void test1() {  
    BeanFactory beanFactory =  new ClassPathXmlApplicationContext("chapter2/namingbean1.xml");  
    //根据类型获取bean  
    HelloApi helloApi = beanFactory.getBean(HelloApi.class);  
    helloApi.sayHello();  
} 

2. 指定唯一id=“bean”

@Test  
public void test2() {  
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean2.xml");  
    //根据id获取bean  
    HelloApi bean = beanFactory.getBean("bean", HelloApi.class);  
    bean.sayHello();  
}

3. 指定唯一name=“bean” @Test内代码同上

4. xml里面 name 和 id 都有写,那么id是标识符,name是别名

  <bean id=”bean1”name=”alias1”  class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/>  

<!-- 如果id和name一样,IoC容器能检测到,并消除冲突 -->  

<bean id="bean3" name="bean3" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  

@Test  
public void test4() {  
  BeanFactory beanFactory =  new ClassPathXmlApplicationContext("chapter2/namingbean4.xml");  
    //根据id获取bean  
    HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);  
    bean1.sayHello();  
    //根据别名获取bean  
    HelloApi bean2 = beanFactory.getBean("alias1", HelloApi.class);  
    bean2.sayHello();  
//根据id获取bean HelloApi bean3 = beanFactory.getBean("bean3", HelloApi.class); bean3.sayHello(); String[] bean3Alias = beanFactory.getAliases("bean3"); //因此别名不能和id一样,如果一样则由IoC容器负责消除冲突 Assert.assertEquals(0, bean3Alias.length); }

5. 指定多个name,多个name用“,”、“;”、“ ”分割,第一个被用作标识符,其他的(alias1、alias2、alias3)是别名,所有标识符也必须在Ioc容器中唯一;  

<bean name=” bean1;alias11,alias12;alias13 alias14”  class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/>     

<!-- 当指定id时,name指定的标识符全部为别名 -->  

<bean id="bean2" name="alias21;alias22"  class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> 

@Test  
public void test5() {  
  BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean5.xml");  
    //1根据id获取bean  
    HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);  
    bean1.sayHello();  
    //2根据别名获取bean  
    HelloApi alias11 = beanFactory.getBean("alias11", HelloApi.class);  
    alias11.sayHello();  
    //3验证确实是四个别名         
    String[] bean1Alias = beanFactory.getAliases("bean1");  
    System.out.println("=======namingbean5.xml bean1 别名========");  
    for(String alias : bean1Alias) {  
        System.out.println(alias);  
    }  
    Assert.assertEquals(4, bean1Alias.length);  
    
  //根据id获取bean HelloApi bean2 = beanFactory.getBean("bean2", HelloApi.class); bean2.sayHello(); //2根据别名获取bean HelloApi alias21 = beanFactory.getBean("alias21", HelloApi.class); alias21.sayHello(); //验证确实是两个别名 String[] bean2Alias = beanFactory.getAliases("bean2"); System.out.println("=======namingbean5.xml bean2 别名========"); for(String alias : bean2Alias) { System.out.println(alias); } Assert.assertEquals(2, bean2Alias.length); }

6. 指定了唯一别名alias

  <bean name="bean" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> 

  <alias alias="alias1" name="bean"/> 

  <alias alias="alias2" name="bean"/> 

@Test  
public void test6() {  
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean6.xml");  
    //根据id获取bean  
    HelloApi bean = beanFactory.getBean("bean", HelloApi.class);  
    bean.sayHello();  

    //根据别名获取bean  
    HelloApi alias1 = beanFactory.getBean("alias1", HelloApi.class);  
    alias1.sayHello();  
    HelloApi alias2 = beanFactory.getBean("alias2", HelloApi.class);  
    alias2.sayHello();  
    String[] beanAlias = beanFactory.getAliases("bean");  
    System.out.println("=======namingbean6.xml bean 别名========");  
    for(String alias : beanAlias) {  
        System.out.println(alias);  
   }  
   System.out.println("=======namingbean6.xml bean 别名========");  
   Assert.assertEquals(2, beanAlias.length);  
 } 

注:从定义来看,name或id如果仅仅指定它们中的一个时会作为“标识符”。而id和name同时存在时呢?这是因为当使用基于XML的配置元数据时,在XML中id是一个真正的XML id属性,因此当其他的定义来引用这个id时就体现出id的好处了,可以利用XML解析器来验证引用的这个id是否存在,从而更早的发现是否引用了一个不存在的bean,而使用name,则可能要在真正使用bean时才能发现引用一个不存在的bean。

Bean实例化:

1. 构造器 constructor-arg

2. 设值 properties

3. 使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean。

静态工厂类代码:

public class HelloApiStaticFactory {  
    //工厂方法  
    public static HelloApi newInstance(String message) {  
           //返回需要的Bean实例  
           return new HelloImpl2(message);  
  }  
}  

xml:<!-- 使用静态工厂方法 -->  

<bean id="bean3" class="cn.javass.spring.chapter2.HelloApiStaticFactory" factory-method="newInstance">  

     <constructor-arg index="0" value="Hello Spring!"/>  

</bean> 

@Test  
public void testInstantiatingBeanByStaticFactory() {  
       //使用静态工厂方法  
       BeanFactory beanFactory = new ClassPathXmlApplicationContext("chaper2/instantiatingBean.xml");  
       HelloApi bean3 = beanFactory.getBean("bean3", HelloApi.class);  
       bean3.sayHello();  
}

4.  使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样。

实例工厂类:

package cn.javass.spring.chapter2;  
public class HelloApiInstanceFactory {  
  public HelloApi newInstance(String message) {  
          return new HelloImpl2(message);  
   }  
}

xml:

<!—1、定义实例工厂Bean -->  

<bean id="beanInstanceFactory"  class="cn.javass.spring.chapter2.HelloApiInstanceFactory"/>  

<!—2、使用实例工厂Bean创建Bean -->  

<bean id="bean4"  factory-bean="beanInstanceFactory"   factory-method="newInstance">  

   <constructor-arg index="0" value="Hello Spring!"></constructor-arg>  

</bean>

@Test  
public void testInstantiatingBeanByInstanceFactory() {  
    //使用实例工厂方法  
       BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/instantiatingBean.xml");  
       HelloApi bean4 = beanFactory.getBean("bean4", HelloApi.class);  
       bean4.sayHello();  
}  

 

 

  到到目前为止,我们只能通过简单的实例化Bean,没有涉及Bean之间关系。接下来一章让我们进入配置Bean之间关系章节,也就是依赖注入。 

posted on 2019-03-10 10:57  pinyi  阅读(149)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3