疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Spring之基于注解的配置


 

       首先使用注解需要在spring配置文件中添加配置项
 
  <context:annotation-config />
 
  @Autowired 自动装配属性
 
  @Autowired不仅可以标注在set方法和属性上,甚至可以标注在需要自动装配Bean引用的任意方法上(也包括构造函数)。
 
  @Autowired不会受private关键字的影响,即使是私有的变量,它任然可以被装配。当使用了@Autowired注解时,Spring就会尝试对该方法或属性执行byType自动装配。
 
  但是,有两种情况下,@Autowired注解会受到影响,应用中只能有一个Bean适合装配到@Autowired注解所标注的属性或参数中。如果没有匹配的Bean,或者存在多个匹配的Bean,@Autowired就会注入失败。
 
  解决办法:默认情况下,@Autowired具有强契约特征,其所标注的属性或参数必须是可装配的。如果没有Bean可以装配到@Autowired所标注的属性或参数中,自动装配就会失败,抛出NoSuchBeanDefinitionException,但属性不一定必须要装配,NULL值也可以接受。在这种情况下,可以通过设置@Autowired的required属性为false来配置自动装配是可选的。例如
 
  @Autowired(required=false)
 
  这种情况下,Spring会尝试装配所标注的属性或参数,但是如果没有找到与之匹配的Bean时,应用程序就不会发生任何问题,所标注的属性值就会为NULL,required属性可以用于@Autowired注解所使用的任何地方。但当使用构造器装配时,只有一个构造器可以将@Autowired的required的属性设置为true。其他使用@Autowired注解所标注的构造方法只能将required属性设置为false。此外,当使用@Autowired标注多个构造器的时候,Spring就会从所有满足装配条件的构造器中选择入参最多的构造器。
 
  另一方面,问题在于或许spring并不缺少适合自动装配的Bean,可能会有多个适合装配的Bean。@Autowired没有办法选择哪一个Bean才是真正需要装配的,所以会抛出NoSuchBeanDefinitionException异常,表明装配失败了。
 
  为了帮助@Autowired鉴别哪一个Bean才是我们需要的,可以配合使用@Qualifier注解。例如
 
      @Autowired
 
      @Qualifier(name="beanId")
 
    @Qualifier注解将尝试注入name属性中指定名称的Bean。
 
 
    既然可以使用注解为Spring的Bean自动装配其他Bean的引用,同样可以使用注解来装配简单的值。Spring3.0引入了@Value,它是一个新的装配注解,可以让我们使用注解装配String类型的值和基本类型的值,例如int、boolean。我们可以通过@Value直接标注某个属性、方法或者方法参数,并传入一个String类型的表达式来装配属性。例如
    @Value("lvmingyin")
    private String name;
    但是,这些值我们通常可以直接在Java代码中编写,为什么还要在@Value的属性中设置呢,在这种情况下,@Value显得有些多余。
    实际上,装配简单的值并不是@Value所擅长的,借助SpEL表达式,@Value被赋予了魔力,在运行时通过SpEL动态计算复杂的表达式的值并把结果装配到Bean的属性中。这一特性也使得@Value注解称为强大的装配可选方案。
    例如,与其设置一个硬编码的静态值,不如使用SpEL从系统属性中获取一个值:
    @Value("#{systemProperties.myFavoritesSong}")
    private String song;
 
    在Spring配置中增加<context:annotation-config/>时能够有助于消除配置文件中的<property/>,但还是需要在配置文件中使用<bean>元素显式定义Bean。
    在Spring中海油一种技巧。<context:component-scan />元素除了完成和<context:annotation-config />一样的工作,还允许自动检测Bean和定义Bean。这以为着不使用<bean>元素,Spring应用中大多数Bean都能够实现定义和装配。
    为了配置Spring自动检测,需要使用<context:component-scan />元素来代替<context:annotation-config />元素。
    
 
    <context:component-scan base-package="com.lmy.spring"></context:component-scan>
    
 
    <context:component-scan />元素会扫描指定的包及其所有子包,并查找出能够自动注册为Spring Bean的类。base-package属性标识了<context:component-scan />元素所扫描的包。
    默认情况下,<context:component-scan />查找使用构造型(stereotype)注解所标注的类,这些特殊的注解如下:
    @Component---通用的构造型注解,标识该类为Spring组件。
    @Controller---标识该类定义为Spring MVC controller。
    @Repository---标识将该类定义为数据仓库。
    @Service---标识将该类定义为服务
    例如,需要声明一个Bean。可以配置<context:component-scan />元素并使用@Component注解标识这个类,从而消除显式的<bean/>定义
    package com.lmy.spring;
    @Component
    public class Dog{}
    Spring扫描com.lmy.spring包时,会发现使用@Component注解所标注的Dog,并自动地把它注册为Spring Bean。Bean的ID默认为无限定类名。在这种情况下,Dog Bean的ID为dog。
    还可以指定@Component注解的参数显式的指定Bean的ID。
    @Component("kala")
    public class Dog{}
    来声明一个ID为kala类型为Dog的Bean。
 
    还可以通过配置<context:include-filter />或者<context:exclude-filter/>调整扫描行为。如下所示:
      
 
<context:component-scan base-package="com.lmy.spring">
      <context:include-filter type="assignable" expression="com.lmy.spring.Animal" />
</context:component-scan>
 
    <context:include-filter />的type和expression属性一起协作来定义组件扫描策略。在这种情况下,我们要求派生于Animal的所有类自动注册为Spring Bean。我们还可以选择如下任意一种过滤器:
      annotation:过滤器扫描使用注解所标注的那些类,通过expression属性指定要扫描的注解。
      assignable:过滤器扫描派生于expression属性所指定类型的那些类。
      aspectj:过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类。
      custom:使用自定义的org.springframework.core.type.TypeFilter实现类,该类由expression属性指定。
      regex:过滤器扫描类的名称与expression属性所指定的正则表达式所匹配的那些类。
    除了使用<context:include-filter />告知<context:component-scan/>哪些类需要注册为Spring Bean以外,我们还可以使用<context:exclude-filter />来告知 <context:component-scan/>哪些类不需要注册为Spring Bean。
    例如除了使用自定义注解@SkipIt的类,其他所有的Animal实现都要注册为Spring Bean
 
<context:component-scan base-package="com.lmy.spring">
<context:include-filter type="assignable" expression="com.lmy.spring.Animal" />
<context:exclude-filter type="annotation" expression="com.lmy.spring.SkipIt" />
</context:component-scan>
    除了使用注解以外,还有一种基于Java的配置,主要是使用@Configuration和@Bean来完成声明的
 
    在类上使用@Configuration标识告诉Spring,这个类包含一个或多个Spring Bean的定义。
 
    
    
 
复制代码
@Configuration
public class AnimalFactory{
 
      //使用@Bean标识一个方法
      @Bean
      public Dog kala(){
        return new Dog();
      }
}
复制代码
  这个方法就是Java配置,他等价于XML所配置的<bean>元素。@Bean告知Spring这个方法返回一个对象,该对象应该被注册在Spring上下文中的一个Bean。方法名是这个Bean的ID。在该方法中实现的所有逻辑本质上都是为了创建Bean。
 
  配置完成了,如何使用基于Java的配置注入呢。很简单,先声明一个xiaohuang Bean。
 
 
@Bean
public Dog xiaohuang(){
  return new Dog("小黄");      
}
然后创建一个Person Bean,通过构造器为他装配xiaohuang。
 
@Bean
public Person zhuren(){
  return new Person(xiaohuang());  
}
通过引用其他Bean的方法来装配Bean的引用,虽然看起来简单,但是实际上发生的远远超过你的想象。
 
在Spring Java配置中,通过声明方法引用一个Bean并不等同于调用该方法。如果真的这样,每次调用xiaohuang,返回的都是一个新的实例。
 
通过使用@Bean注解标识xiaohuang()方法,会告诉Spring我们希望该方法定义的Bean要被注册进Spring应用上下文中。因此,在其他Bean的声明方法中引用这个方法时,Spring 都会拦截该方法的调用,并尝试在应用上下文中查找该Bean,而不是创建一个新的实例。