spring学习笔记2--bean装配

来源:互联网 发布:外观设计软件 编辑:程序博客网 时间:2024/06/03 21:12

bean装配

Spring提供了三种主要的装配机制:

  • 在XML中进行显式配置。
  • 在Java中进行显式配置。
  • 隐式的bean发现机制和自动装配

自动装配

Spring从两个角度来实现自动化装配:

  • 组件扫描(component scanning):Spring会自动发现应用上下文
    中所创建的bean。
  • 自动装配(autowiring):Spring自动满足bean之间的依赖。
@Componentpublic class TestBean{}@Configuration@ComponentScanpublic class ConfigBean{}

@ComponentScan开启组件扫描,如果没有其它配置默认会扫描与配置类相同的包及其子包。也可以是使用xml开启:

<contest:component-scan base-package="x.x.x"/>

使用spring创建一个测试

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=someclass.class)public class Test{    @AutoWire    private TestClass test;    @Test    public void test(){        Assert.assertNotNull(test);    }}

bean id

spring应用上下文会为所有的bean设定一个id,默认为类名的第一个字母小写。如果想自己设置,可以:

@Component("myid")

也可以:

Named("myid") public class myclass

扫描基础包

@Configuration@ComponentScan(basePackages={"pacakge1","pacakge2"})public class ConfigBean{}

另外一种指定包扫描的方法为:

@ComponentScan(basePackageClasses={A.class,B.class})这些类所在的包将会成为组件扫描的包。

自动装配

@Autowired注解可以用在构造器,Setter方法或者其它方法,spring会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配,那么它将会被这个bean装配进来。如果没有则会抛出异常。为了避免异常,可以:

@Autowired(required=false)

如果有多个bean符合需求,也会抛出异常。

@Inject:java依赖注入规范定义的一个注解。也可以用来自动装配。

@Autowired和@Inject,@Resource

  1. @Autowired和@Inject
    默认 autowired by type
    可以 通过@Qualifier 显式指定 autowired by qualifier name。
  2. @Resource
    默认 autowired by field name
    如果 autowired by field name失败,会退化为 autowired by type
    可以 通过@Qualifier 显式指定 autowired by qualifier name
    如果 autowired by qualifier name失败,会退化为 autowired by field name。但是这时候如果 autowired by field name失败,就不会再退化为autowired by type了。
  3. @Autowired和@Inject基本是一样的,因为两者都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入。但是@Resource是个例外,它使用的是CommonAnnotationBeanPostProcessor来处理依赖注入。
  4. @Inject是jsr330规范的实现,而@Autowired是spring的实现,@Resource则是jsr250的实现。

显示装配bean

java方式:在添加了@Configuration注解的配置类中添加方法返回该bean:

@Configurationpublic class CDPlayerConfig {  @Bean(name="xxxx")  public CompactDisc compactDisc() {    return new SgtPeppers();  }  //没有name属性的话bean的id默认为方法的名字  @Bean  public CDPlayer cdPlayer(CompactDisc compactDisc) {    return new CDPlayer(compactDisc);  }}

可以使用多个注解类,如果一个注解类要用到其中的一个注解类的bean的话,可以使用@import导入.如果用到xml声明的bean,可以把相应的配置文件导入。

@Configuration@Import(CDPlayerConfig.class)@ImportResource("classpath:cd-config.xml")public class SoundSystemConfig {}

在xml中如何引用javaconfig配置的bean? 可以使用标签将配置类导入。就可使用了。也可以创建一个组合xml,将配置文件和配置类一起导入,即根配置,并在根配置中启动组件扫描。

<bean class="soundsystem.CDConfig" />  <bean id="cdPlayer"        class="soundsystem.CDPlayer"        c:cd-ref="compactDisc" />

创建一个根配置

<beans xmlns=""><bean class="xxxConfig/><import resource="xxx.xml"/></beans>

条件化bean

@Bean  @Conditional(MagicExistsCondition.class)  public MagicBean magicBean() {    return new MagicBean();  }  ```传给该注解的类可以是任意实现了Condition接口的实现类。该接口根据matches返回的结果来决定是否实例化bean.public inteface Condition{    boolean matches(ConditionContext ctx,AnnotatedTypeMedtadata metadata);}

@Profile也使用了@Conditional注解,并且引用ProfileCondition作为Condition实现。

处理自动装配歧义性

当有多个bean满足装配的条件时,如何解决?
有多种方法:
1. 首选bean.使用@Primary注解。当使用xml时可指定的primary属性为true.
2. 使用@Qualifier(“beanid”)指定bean的id.标识唯一性。如果没有则会使用默认的限定符命名方式。在bean声明上添加@Qualifier注解。例
如,它可以与@Component组合使用.

@Component@Qualifier("xxxx")public class testBean{}

spring bean的常见作用域

  • 单例(Singletion)
  • 原型(Prototype)
  • 会话(Session)
  • 请求(Request)

声明作用域:

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

使用会话和请求作用域

@Component@Scope{value=WebApplicationContext.SOCPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)}public ShoppingCart cart(){...}

proxyMode解决了这样一个问题,:将会话范围内的bean注入到单例bean中时,如果用户没有请求系统会话bean不存在或多个用户就会有多分session bean。使用proxyMode便会注入一个代理,当真正调用会话bean的方法时,代理会对其进行懒解析并将调用委托
给会话作用域内真正的ShoppingCart bean。,proxyMode属性被设置成了
ScopedProxyMode.INTERFACES,这表明这个代理要实现
ShoppingCart接口,并将调用委托给实现bean。如果ShoppingCart是类的话,要将proxyMode属性设置
为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标
类扩展的方式创建代理。

在xml中声明作用域代理

<bean id="cart" class="com.myapp.ShoppingCart" scope="session"><aop:scoped-proxy/></bean>

默认情况下,它会使用CGLib创建目标类的代理。但是我们也可
以将proxy-target-class属性设置为false,进而要求它生成基
于接口的代理:

运行时值注入

声明属性源并通过spring的Enviroment来检索属性:

@Configuration@PropertySource("classpath:xxx.properties")public class Config{    @Autowired    Enviroment ev;    @Bean    public Person person(){        return new Person(env.getProperty("name"),evn.getProperty("id"));    }}

在java配置或xml配置中也可使用占位符的形式。
如果使用组件扫描和自动装配,则用@Value注解

public Person(@Value("${person.id}")String id,    @Value("${person.name}")String name){        this.id=id;        this.name = name;    }

为了使用占位符,必须配置一个PropertySourcePlaceholderConfigurer.

@Beanpublic static PropertySourcePlaceholderConfigurer placeholderConfigurer(){    return new PropertySourcePlaceholderConfigurer();}

xml中的会为你生成PropertySourcePlaceholderConfigurer.

junit基于控制台的输出编写断言:

@Rulepublic final StandardOutputStreamLog log = new StandardOutputStreamLog();@Testpublic void test(){    assertEquals("some log",log.getLog());}
原创粉丝点击