当前位置: 移动技术网 > IT编程>开发语言>Java > 详解Java的Spring框架中的注解的用法

详解Java的Spring框架中的注解的用法

2019年07月22日  | 移动技术网IT编程  | 我要评论

1. 使用spring注解来注入属性

1.1. 使用注解以前我们是怎样注入属性的
类的实现:

class usermanagerimpl implements usermanager { 
  private userdao userdao; 
  public void setuserdao(userdao userdao) { 
    this.userdao = userdao; 
  } 
  ... 
}

配置文件:

<bean id="usermanagerimpl" class="com.kedacom.spring.annotation.service.usermanagerimpl"> 
  <property name="userdao" ref="userdao" /> 
</bean> 
<bean id="userdao" class="com.kedacom.spring.annotation.persistence.userdaoimpl"> 
  <property name="sessionfactory" ref="mysessionfactory" /> 
</bean>

1.2. 引入@autowired注解(不推荐使用,建议使用@resource)
类的实现(对成员变量进行标注)

public class usermanagerimpl implements usermanager { 
  @autowired 
  private userdao userdao; 
  ... 
}

或者(对方法进行标注)

usermanagerimpl implements usermanager { 
  private userdao userdao; 
  @autowired 
  public void setuserdao(userdao userdao) { 
    this.userdao = userdao; 
  } 
  ... 
}

配置文件

<bean id="usermanagerimpl" class="com.kedacom.spring.annotation.service.usermanagerimpl" /> 
<bean id="userdao" class="com.kedacom.spring.annotation.persistence.userdaoimpl"> 
  <property name="sessionfactory" ref="mysessionfactory" /> 
</bean>

@autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。以上两种不同实现方式中,@autowired的标注位置不同,它们都会在spring在初始化usermanagerimpl这个bean时,自动装配userdao这个属性,区别是:第一种实现中,spring会直接将userdao类型的唯一一个bean赋值给userdao这个成员变量;第二种实现中,spring会调用setuserdao方法来将userdao类型的唯一一个bean装配到userdao这个属性。

1.3. 让@autowired工作起来
要使@autowired能够工作,还需要在配置文件中加入以下代码

class="org.springframework.beans.factory.annotation.autowiredannotationbeanpostprocessor" />

1.4. @qualifier
@autowired是根据类型进行自动装配的。在上面的例子中,如果当spring上下文中存在不止一个userdao类型的bean时,就会抛出beancreationexception异常;如果spring上下文中不存在userdao类型的bean,也会抛出beancreationexception异常。我们可以使用@qualifier配合@autowired来解决这些问题。
1. 可能存在多个userdao实例

@autowired 
public void setuserdao(@qualifier("userdao") userdao userdao) { 
  this.userdao = userdao; 
}

这样,spring会找到id为userdao的bean进行装配。
2. 可能不存在userdao实例

@autowired(required = false) 
public void setuserdao(userdao userdao) { 
  this.userdao = userdao; 
} 

1.5. @resource(jsr-250标准注解,推荐使用它来代替spring专有的@autowired注解)
spring 不但支持自己定义的@autowired注解,还支持几个由jsr-250规范定义的注解,它们分别是@resource、@postconstruct以及@predestroy。
@resource的作用相当于@autowired,只不过@autowired按bytype自动注入,而@resource默认按byname自动注入罢了。@resource有两个属性是比较重要的,分别是name和type,spring将@resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byname的自动注入策略,而使用type属性时则使用bytype自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byname自动注入策略。
@resource装配顺序

如果同时指定了name和type,则从spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
如果既没有指定name,又没有指定type,则自动按照byname方式进行装配(见2);如果没有匹配,则回退为一个原始类型(userdao)进行匹配,如果匹配则自动装配;
1.6. @postconstruct(jsr-250)
在方法上加上注解@postconstruct,这个方法就会在bean初始化之后被spring容器执行(注:bean初始化包括,实例化bean,并装配bean的属性(依赖注入))。
它的一个典型的应用场景是,当你需要往bean里注入一个其父类中定义的属性,而你又无法复写父类的属性或属性的setter方法时,如: 

public class userdaoimpl extends hibernatedaosupport implements userdao { 
  private sessionfactory mysessionfacotry; 
  @resource 
  public void setmysessionfacotry(sessionfactory sessionfacotry) { 
    this.mysessionfacotry = sessionfacotry; 
  } 
  @postconstruct 
  public void injectsessionfactory() { 
    super.setsessionfactory(mysessionfacotry); 
  } 
  ... 
}

这里通过@postconstruct,为userdaoimpl的父类里定义的一个sessionfactory私有属性,注入了我们自己定义的sessionfactory(父类的setsessionfactory方法为final,不可复写),之后我们就可以通过调用super.getsessionfactory()来访问该属性了。


1.7. @predestroy(jsr-250)
在方法上加上注解@predestroy,这个方法就会在bean初始化之后被spring容器执行。由于我们当前还没有需要用到它的场景,这里不不去演示。其用法同@postconstruct。

1.8. 使用<context:annotation-config />简化配置
spring2.1添加了一个新的context的schema命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的,它仅提供元数据信息。要使元数据信息真正起作用,必须让负责处理这些元数据的处理器工作起来。
autowiredannotationbeanpostprocessor和commonannotationbeanpostprocessor就是处理这些注释元数据的处理器。但是直接在spring配置文件中定义这些bean显得比较笨拙。spring为我们提供了一种方便的注册这些beanpostprocessor的方式,这就是<context:annotation-config />:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:context="http://www.springframework.org/schema/context" 
  xsi:schemalocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
  <context:annotation-config /> 
</beans>

<context:annotationconfig />将隐式地向spring容器注册autowiredannotationbeanpostprocessor、commonannotationbeanpostprocessor、 persistenceannotationbeanpostprocessor以及requiredannotationbeanpostprocessor这4个beanpostprocessor。

2. 使用spring注解完成bean的定义
以上我们介绍了通过@autowired或@resource来实现在bean中自动注入的功能,下面我们将介绍如何注解bean,从而从xml配置文件中完全移除bean定义的配置。

2.1. @component(不推荐使用)、@repository、@service、@controller
只需要在对应的类上加上一个@component注解,就将该类定义为一个bean了:

@component 
public class userdaoimpl extends hibernatedaosupport implements userdao { 
  ... 
}

使用@component注解定义的bean,默认的名称(id)是小写开头的非限定类名。如这里定义的bean名称就是userdaoimpl。你也可以指定bean的名称:
@component("userdao")
@component是所有受spring管理组件的通用形式,spring还提供了更加细化的注解形式:@repository、@service、@controller,它们分别对应存储层bean,业务层bean,和展示层bean。目前版本(2.5)中,这些注解与@component的语义是一样的,完全通用,在spring以后的版本中可能会给它们追加更多的语义。所以,我们推荐使用@repository、@service、@controller来替代@component。

2.2. 使用<context:component-scan />让bean定义注解工作起来

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:context="http://www.springframework.org/schema/context" 
  xsi:schemalocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
  <context:component-scan base-package="com.kedacom.ksoa" /> 
</beans>

这里,所有通过<bean>元素定义bean的配置内容已经被移除,仅需要添加一行<context:component-scan />配置就解决所有问题了——spring xml配置文件得到了极致的简化(当然配置元数据还是需要的,只不过以注释形式存在罢了)。<context:component-scan />的base-package属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。
<context:component-scan />还允许定义过滤器将基包下的某些类纳入或排除。spring支持以下4种类型的过滤方式:

过滤器类型 表达式范例 说明
注解 org.example.someannotation 将所有使用someannotation注解的类过滤出来
类名指定 org.example.someclass 过滤指定的类
正则表达式 com\.kedacom\.spring\.annotation\.web\..* 通过正则表达式过滤一些类
aspectj表达式 org.example..*service+ 通过aspectj表达式过滤一些类

以正则表达式为例,我列举一个应用实例:

<context:component-scan base-package="com.casheen.spring.annotation"> 
  <context:exclude-filter type="regex" expression="com\.casheen\.spring\.annotation\.web\..*" /> 
</context:component-scan>

值得注意的是<context:component-scan />配置项不但启用了对类包进行扫描以实施注释驱动bean定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了autowiredannotationbeanpostprocessor和commonannotationbeanpostprocessor),因此当使用<context:component-scan />后,就可以将<context:annotation-config />移除了。

2.3. 使用@scope来定义bean的作用范围
在使用xml定义bean时,我们可能还需要通过bean的scope属性来定义一个bean的作用范围,我们同样可以通过@scope注解来完成这项工作:

@scope("session") 
@component() 
public class usersessionbean implements serializable { 
  ... 
}

3.在使用annotation之前定义三个bean之间的关系是这样的

package com.baobaotao;
public class office {
  private string officeno =”001”;
 
  //省略 get/setter
 
  @override
  public string tostring() {
    return "officeno:" + officeno;
  }
}

ackage com.baobaotao;
 
public class car {
  private string brand;
  private double price;
 
  // 省略 get/setter
 
  @override
  public string tostring() {
    return "brand:" + brand + "," + "price:" + price;
  }
}

package com.baobaotao;
 
public class boss {
  private car car;
  private office office;
 
  // 省略 get/setter
 
  @override
  public string tostring() {
    return "car:" + car + "\n" + "office:" + office;
  }
}

配置文件如下:

<?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-2.5.xsd">
  <bean id="boss" class="com.baobaotao.boss">
    <property name="car" ref="car"/>
    <property name="office" ref="office" />
  </bean>
  <bean id="office" class="com.baobaotao.office">
    <property name="officeno" value="002"/>
  </bean>
  <bean id="car" class="com.baobaotao.car" scope="singleton">
    <property name="brand" value=" 红旗 ca72"/>
    <property name="price" value="2000"/>
  </bean>
</beans>

测试文件如下:

import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;
public class annoioctest {
 
  public static void main(string[] args) {
    string[] locations = {"beans.xml"};
    applicationcontext ctx = 
      new classpathxmlapplicationcontext(locations);
    boss boss = (boss) ctx.getbean("boss");
    system.out.println(boss);
  }
}

 
4.接下来我们可以使用autowired来注解,他可以对成员变量,方法及构造函数进行标准,完成自动装配的工作。

autoware来注解成员变量的用法

package com.baobaotao;
import org.springframework.beans.factory.annotation.autowired;
 
public class boss {
 
  @autowired
  private car car;
 
  @autowired
  private office office;
 
  …
}

相应的配置文件如下:

<?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-2.5.xsd">
 
  <!-- 该 beanpostprocessor 将自动起作用,对标注 @autowired 的 bean 进行自动注入 -->
  <bean class="org.springframework.beans.factory.annotation.
    autowiredannotationbeanpostprocessor"/>
 
  <!-- 移除 boss bean 的属性注入配置的信息 -->
  <bean id="boss" class="com.baobaotao.boss"/>
 
  <bean id="office" class="com.baobaotao.office">
    <property name="officeno" value="001"/>
  </bean>
  <bean id="car" class="com.baobaotao.car" scope="singleton">
    <property name="brand" value=" 红旗 ca72"/>
    <property name="price" value="2000"/>
  </bean>
</beans>

autoware也可以用在setter方法及构造函数上

package com.baobaotao;
 
public class boss {
  private car car;
  private office office;
 
   @autowired
  public void setcar(car car) {
    this.car = car;
  }
 
  @autowired
  public void setoffice(office office) {
    this.office = office;
  }
  …
}

package com.baobaotao;
 
public class boss {
  private car car;
  private office office;
 
  @autowired
  public boss(car car ,office office){
    this.car = car;
    this.office = office ;
  }
 
  …
}

当候选bean的数目为0时,我们可以使用@autowired(required = false)来防止spring找不到bean时报错。

当有多个候选bean的时候,我们可以通过@qualifier 注释指定注入 bean 的名称。

@autowired 和 @qualifier 结合使用时,自动注入的策略就从 bytype 转变成 byname 了。@autowired 可以对成员变量、方法以及构造函数进行注释,而 @qualifier 的标注对象是成员变量、方法入参、构造函数入参。正是由于注释对象的不同,所以 spring 不将 @autowired 和 @qualifier 统一成一个注释类。

5.@resorce是按照名字来进行反射,他有两个参数,name和type,使用name即按照byname来映射,使用type即按照bytype来进行映射。

package com.baobaotao;
 
import javax.annotation.resource;
 
public class boss {
  // 自动注入类型为 car 的 bean
  @resource
  private car car;
 
  // 自动注入 bean 名称为 office 的 bean
  @resource(name = "office")
  private office office;
}
@postconstructor和predestory是用来注解类初始化后和销毁前的方法。 


package com.baobaotao;
 
import javax.annotation.resource;
import javax.annotation.postconstruct;
import javax.annotation.predestroy;
 
public class boss {
  @resource
  private car car;
 
  @resource(name = "office")
  private office office;
 
  @postconstruct
  public void postconstruct1(){
    system.out.println("postconstruct1");
  }
 
  @predestroy
  public void predestroy1(){
    system.out.println("predestroy1"); 
  }
  …
}

6.@compent可以直接定义bean,这样xml配置文件中就不需要配置bean了

package com.baobaotao;
 
import org.springframework.stereotype.component;
 
@component
public class car {
  …
}

package com.baobaotao;
 
import org.springframework.stereotype.component;
 
@component
public class office {
  private string officeno = "001";
  …
}

package com.baobaotao;
 
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.beans.factory.annotation.required;
import org.springframework.beans.factory.annotation.qualifier;
import org.springframework.stereotype.component;
 
@component("boss")
public class boss {
  @autowired
  private car car;
 
  @autowired
  private office office;
  …
}

@component 有一个可选的入参,用于指定 bean 的名称,在 boss 中,我们就将 bean 名称定义为“boss”。一般情况下,bean 都是 singleton 的,需要注入 bean 的地方仅需要通过 bytype 策略就可以自动注入了,所以大可不必指定 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"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemalocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context-2.5.xsd">
  <context:component-scan base-package="com.baobaotao"/>
</beans>

7.@scope可以用来指定其目标

package com.baobaotao;
import org.springframework.context.annotation.scope;
…
@scope("prototype")
@component("boss")
public class boss {


spring 2.5 中除了提供 @component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@repository、@service 和 @controller。在目前的 spring 版本中,这 3 个注释和 @component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(web 层)相对应。虽然目前这 3 个注释和 @component 相比没有什么新意,但 spring 将在以后的版本中为它们添加特殊的功能。所以,如果 web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用 @repository、@service 和 @controller 对分层中的类进行注释,而用 @component 对那些比较中立的类进行注释。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网