spring注解

why(为什么要使用spring注解):

有助于减少甚至消除配置<property>元素和<constructor-arg>元素,让spring自动识别如何装配bean的依赖关系。

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   
      <bean id="tiger" class="org.xrq.action.by.Tiger" />
      
      <bean id="zoo" class="org.xrq.action.by.Zoo">
         <property name="animal" ref="tiger" />
   </bean>
         
 </beans>

<property>标签过多会引发两个问题:

  • 如果一个Bean中要注入的对象过多,比如十几二十个(这是很正常的),那将导致Spring配置文件非常冗长,可读性与维护性差
  • 如果一个Bean中要注入的对象过多,配置麻烦且一不小心就容易出错

因此,为了解决使用<property>标签注入对象过多的问题,Spring引入自动装配机制,简化开发者配置难度,降低xml文件配置大小。

使用注解自动装配与在xml中使用autowire属性自动装配并没有太大差别,但是使用注解方式允许更细粒度的自动装配,可以选择性的标注某一个属性来对其应用自动装配。

spring容器默认禁用注解装配,所以在使用基于注解的自动装配前,我们需要在spring配置中启用它。最简单的启用方式是使用spring的context命名空间配置中的<context:annotation-config>元素

在beans标签中加入<context:annotation-config/>即是告诉spring我们打算使用基于注解的自动装配。一旦配置完成,我们就可以对代码添加注解,标识spring应该为属性、方法、构造器进行自动装配。

spring 3支持几种不同的用于自动装配的注解

 1.spring 自带的@Autowired注解,

 2.JSR-330的@Inject注解:是为了统一各种依赖注入框架的编程规范,JCP发布了是最新的规范,称之为JSR-330,其中@Inject是其核心部件,该注解几乎可以完全替换spring的@Autowired,

     可以用来自动装配方法,属性,构造器,基本上等同于@Autowired

 3.JSR-250的@Resource注解

 

@Value:spring 3.0引入的,它是一个新的装配注解,可以让我们使用注解装配string类型的值和基本类型的值,如int ,boolean

@Value("Eruption")

private String song;

表明spring为string类型的属性装配了一个string 类型的值

 

<content:annotation-config>有助于完全消除spring配置中的<property>和<constructor-arg>元素,但是我们仍然需要使用<bean>元素显式的定义bean.

但是spring还有另一个技巧,<context:annotation-scan>元素除了完成与<context:annotation-config>一样的工作,还允许spring自动检测bean和定义bean.这就意味着不使用<bean>元素,spring

应用中的大多数bean都能够实现定义和装配。<context:annotation-scan>元素会扫描指定的包及其所有的子包,并查找出能够自动注册为spring bean的类,那么它又是如何知道哪些类要注册为spring的bean呢?

默认情况下,<context:annotation-scan>查找使用构造型注解所标注的类,这些特殊的注解如下:

@Component:通用的构造型注解,标识该类为spring组件

@Controller:标识将该类定义为spring mvc的controller

@Repository:标识将该类定义为数据仓库,一般用于持久化层的 DAO component

@Service:标识将该类定义为服务

使用@Component标注的任意自定义的注解。

 在项目中,我们可以将所有自动扫描组件都用 @Component 注释,Spring 将会扫描所有用 @Component 注释过得组件。 实际上,@Repository 、 @Service 、 @Controller 三种注释是为了加强代码的阅读性而创造的,可以在不同的应用层中,用不同的注释,我们可以在上一个项目的基础上改一下注释

 

package com.springination.springidol

import org.springframework,stereotype.Component;

@Component
public class Guitar implements Instrument{
    public void play(){
     System.out.println("strum strum strum");
   }
}

 

spring 扫描com.springination.springidol包时,会发现使用@Component 注解所标注的Guitar,并将其自动注册为spring的bean ,bean的id=guitar(无限定类名)

如果出现@Component("eddie"),则beanid=eddie,而不是无限定类名

<context:component-scan>也会自动加载使用@Configuration注解所标注的类,@Configuration注解会做为一个标识告诉spring,这个类包含一个或多个spring bean的定义,这此bean的定义是使用@Bean注解所标注的方法

@Bean
public Peromer duke(){
 return new Juggler();
}

这个简单方法就是Java配置,它等价于我们之前使用xml所配置的<bean>元素,@Bean告知spring这个方法将返回一个对象,该对象应该被注册为spring 上下文中的一个bean,方法名将作为该bean的id,在该方法中所实现的所有逻辑都是为了创建一个bean,即new Juggler()对象出来。

 

@Bean
private Poem sonnet29(){
 return new Sonnet29();
}

@Bean
public Performer poeticDuke(){
  return new PoeticJuggler(sonnet29());
}

创建一个PoeticJuggler bean,通过构造器为它装配sonnet29 bean.

注意:在spring的java配置中,通过声明方法引用一个bean并不等同于调用该方法,如果真是这样,每次调用sonnet29(),都将得到该bean 的一个新的实例

通过使用@Bean注解标注sonnet29()方法,会告知spring 我们希望该方法定义的bean要被注册到spring的应用上下文中,因此,在其他bean的声明方法中引用这个方法时

spring会拦截该方法的调用,并尝试在应用上下文中查找该Bean,而不是让方法创建一个新的实例。

 

带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。最简单可行的 @Configuration 类如下所示:

package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
   @Bean 
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

上面的代码将等同于下面的 XML 配置:

<beans>
   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>

 

example:Instrumentlist 类中有instrument属性,期望自动装配instrument属性

@Autowired

private Instrument instrument;//此处需要删除相应的setter方法

===》等同于

@Autowired

public void setInstrument(Instrument instrument){

      this.instrument = instrument;

}

//当spring发现我们对setInstrument方法使用了@Autowired注解时,spring会尝试对该方法执行byType自动装配

  <bean id="instrument" class="com.zf.springidol.Instrument" />

<bean id="kenny" class="com.zf.springidol.Instrumentlist">

   <property name="animal" ref="instrument" />   //若使用了@Autowired注解其属性instrument后,则这个property就可以删除了

</bean>

如果有足够多的bean都完全满足装配条件,并且都可以被装配到属性或参数中,@Autowired注解没有办法选择哪一个bean才是它真正需要的,此时会抛出一个

NoSuchBeanDefinitionException异常,表示装配失败了。此时可以配合使用@Qualifier注解(此注解是通过指定beanid来缩小装配范围。)

 

自动装配就是让Spring自动满足bean依赖的一种方式,在满足依赖的过程中,会在Spring的上下文中寻找匹配一个bean需求的其他bean。为了声明要进行自动装配,我们可以借助Spring的 @Autowried注解。
比如说CDPlayer类,它在构造器上添加了 @Autowried注解,这表明当创建CDPlayer bean的时候,会通过这个构造器来进行实例化并且会传入一个可设置给CompactDisc类型的bean

 

package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implements MediaPlayer {
  private CompactDisc cd;

  @Autowired
  public CDPlayer(CompactDisc cd) {
    this.cd = cd;
  }

  public void play() {
    cd.play();
  }

}

 

总结一下,自动装配bean的过程:
一、把需要被扫描的类,添加 @Component注解,使它能够被Spring自动发现。
二、通过显示的设置Java代码 @ComponentScan注解或XML配置,让Spring开启组件扫描,并将扫描的结果类创建bean。
三、@Autowried注解能偶实现bean的自动装配,实现依赖注入。

 

 

创建CompactDisc接口:

 

package soundsystem;

public interface CompactDisc {
  void play();
}

 

实现CompactDisc接口:

 

package soundsystem;
import org.springframework.stereotype.Component;

@Component
public class SgtPeppers implements CompactDisc {

  private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
  private String artist = "The Beatles";
  
  public void play() {
    System.out.println("Playing " + title + " by " + artist);
  }
 
}

在SgtPeppers类上使用了 @Component注解,这个注解表明该类会作为组件类,并告知Spring要为这个类创建bean,不需要显示配置SgtPeppers bean。

 

    @Autowired与@Resource异同:

    1° @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

    2° @Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。

    3° @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

 

 

 一个创建自定义注解的例子

public class AnnotionOperator {
    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
        SayHiEmlement element = new SayHiEmlement(); // 初始化一个实例,用于方法调用
        Method[] methods = SayHiEmlement.class.getDeclaredMethods(); // 获得所有方法
        
        for (Method method : methods) {
            SayHiAnnotation annotationTmp = null;
            if((annotationTmp = method.getAnnotation(SayHiAnnotation.class))!=null) // 检测是否使用了我们的注解
                method.invoke(element,annotationTmp.paramValue()); // 如果使用了我们的注解,我们就把注解里的"paramValue"参数值作为方法参数来调用方法
            else
                method.invoke(element, "Rose"); // 如果没有使用我们的注解,我们就需要使用普通的方式来调用方法了
        }
    }

 

 

 

posted on 2018-07-05 09:03  zhufei2007fang  阅读(164)  评论(0编辑  收藏  举报