Maison  >  Article  >  Java  >  Explication détaillée de l'utilisation des annotations dans le framework Spring de Java

Explication détaillée de l'utilisation des annotations dans le framework Spring de Java

高洛峰
高洛峰original
2017-01-23 10:35:501337parcourir

1. Utiliser les annotations Spring pour injecter des attributs

1.1. Comment avons-nous injecté des attributs avant d'utiliser les annotations
Implémentation de la classe :

class UserManagerImpl implements UserManager {
  private UserDao userDao;
  public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
  }
  ...
}

Configuration fichier :

<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. Introduction de l'annotation @Autowired (non recommandé, il est recommandé d'utiliser @Resource)
Implémentation de la classe (annotation des variables membres)

public class UserManagerImpl implements UserManager {
  @Autowired
  private UserDao userDao;
  ...
}

ou (cochez la méthode)

UserManagerImpl implements UserManager {
  private UserDao userDao;
  @Autowired
  public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
  }
  ...
}

Fichier de configuration

<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 peut annoter les variables membres, les méthodes et les constructeurs pour terminer l'assemblage automatique. Dans les deux implémentations différentes ci-dessus, la position de l'annotation @Autowired est différente. Ils assembleront automatiquement l'attribut userDao lorsque Spring initialisera le bean userManagerImpl. La différence est : dans la première implémentation, Spring assemblera directement le seul de type UserDao. Le bean est affecté à la variable membre userDao ; dans la deuxième implémentation, Spring appellera la méthode setUserDao pour assembler le seul bean de type UserDao à l'attribut userDao.

1.3. Laisser @Autowired fonctionner
Pour faire fonctionner @Autowired, vous devez ajouter le code suivant au fichier de configuration

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

1.4. Le qualificateur
@Autowired est automatiquement câblé en fonction du type. Dans l'exemple ci-dessus, s'il y a plus d'un bean de type UserDao dans le contexte Spring, une BeanCreationException sera levée ; s'il n'y a pas de bean de type UserDao dans le contexte Spring, une BeanCreationException sera également levée. Nous pouvons utiliser @Qualifier avec @Autowired pour résoudre ces problèmes.
1. Il peut y avoir plusieurs instances UserDao

@Autowired
public void setUserDao(@Qualifier("userDao") UserDao userDao) {
  this.userDao = userDao;
}

De cette façon, Spring trouvera le bean avec l'identifiant userDao pour l'assemblage.
2. L'instance UserDao peut ne pas exister

   
@Autowired(required = false)
public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
}

1.5. @Resource (annotation standard JSR-250, il est recommandé de l'utiliser à la place de l'annotation propriétaire @Autowired de Spring)
Spring prend non seulement en charge sa propre annotation @Autowired, mais prend également en charge plusieurs annotations définies par la spécification JSR-250, à savoir @Resource, @PostConstruct et @PreDestroy.
La fonction de @Resource est équivalente à @Autowired, sauf que @Autowired est automatiquement injecté par byType, tandis que @Resource est automatiquement injecté par byName par défaut. @Resource a deux attributs importants, à savoir name et type Spring résout l'attribut name de l'annotation @Resource en nom du bean, et l'attribut type se résout en type du bean. Ainsi, si l'attribut name est utilisé, la stratégie d'injection automatique byName est utilisée, et lorsque l'attribut type est utilisé, la stratégie d'injection automatique byType est utilisée. Si ni l'attribut name ni l'attribut type ne sont spécifiés, la stratégie d'injection automatique byName sera utilisée via le mécanisme de réflexion.
@Ordre d'assemblage des ressources

Si le nom et le type sont spécifiés en même temps, le seul bean correspondant sera trouvé à partir du contexte Spring pour l'assemblage. S'il n'est pas trouvé, une exception sera levée.
Si le nom est spécifié, recherchez le bean avec un nom (id) correspondant dans le contexte pour l'assembly. Si aucun bean n'est trouvé, une exception sera levée
Si ni le nom ni le type. est spécifié, l'assemblage sera automatiquement effectué selon byName (voir 2) ; s'il n'y a pas de correspondance, il reviendra à un type primitif (UserDao) pour la correspondance. S'il y a une correspondance, Assemblage automatique
1.6. @PostConstruct (JSR-250)
Ajoutez l'annotation @PostConstruct à la méthode, et cette méthode sera exécutée par le conteneur Spring après l'initialisation du Bean (Remarque : l'initialisation du Bean inclut l'instanciation du Bean et l'assemblage des propriétés du Bean (injection de dépendances)).
Un scénario d'application typique est celui où vous devez injecter une propriété définie dans sa classe parent dans un Bean, mais vous ne pouvez pas remplacer la propriété de la classe parent ou la méthode de définition de la propriété, telle que :

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);
  }
  ...
}

Ici, via @PostConstruct, nous injectons notre propre sessionFactory définie dans une propriété privée sessionFactory définie dans la classe parent de UserDaoImpl (la méthode setSessionFactory de la classe parent est finale et ne peut pas être remplacée), puis nous pouvons accédez à cette propriété en appelant super.getSessionFactory().

1.7. @PreDestroy (JSR-250)
Ajoutez l'annotation @PreDestroy à la méthode, et cette méthode sera exécutée par le conteneur Spring après l'initialisation du Bean. Puisque nous n’avons actuellement aucun scénario dans lequel nous devrions l’utiliser, nous ne le démontrerons pas ici. Son utilisation est la même que celle de @PostConstruct.

1.8. Utilisez bfe8fab089282832fed14fcb6f680c1e pour simplifier la configuration

Spring2.1 ajoute un nouvel espace de noms de schéma de contexte, qui est utile pour les pilotes d'annotation, l'introduction de fichiers de propriétés et le chargement de fonctionnalités telles que le tissage d'époque offre une configuration pratique. Nous savons que l'annotation elle-même ne fait rien, elle fournit uniquement des informations sur les métadonnées. Pour que les informations sur les métadonnées soient vraiment utiles, le processeur responsable du traitement des métadonnées doit être mis à contribution.
AutowiredAnnotationBeanPostProcessor et CommonAnnotationBeanPostProcessor sont des processeurs qui traitent ces métadonnées d'annotation. Mais il est maladroit de définir ces beans directement dans le fichier de configuration Spring. Spring nous offre un moyen pratique d'enregistrer ces BeanPostProcessors, à savoir bfe8fab089282832fed14fcb6f680c1e :

<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>

02b5e3170f8825be11991279b556a682将隐式地向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. 使用5fac6a8af37bdf6785fe01c166cb3779让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>

这里,所有通过60e23eb984d18edbb092da6b8f295aba元素定义Bean的配置内容已经被移除,仅需要添加一行5fac6a8af37bdf6785fe01c166cb3779配置就解决所有问题了——Spring XML配置文件得到了极致的简化(当然配置元数据还是需要的,只不过以注释形式存在罢了)。5fac6a8af37bdf6785fe01c166cb3779的base-package属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。 
5fac6a8af37bdf6785fe01c166cb3779还允许定义过滤器将基包下的某些类纳入或排除。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>

值得注意的是5fac6a8af37bdf6785fe01c166cb3779配置项不但启用了对类包进行扫描以实施注释驱动Bean定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor),因此当使用5fac6a8af37bdf6785fe01c166cb3779后,就可以将bfe8fab089282832fed14fcb6f680c1e移除了。

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 对那些比较中立的类进行注释。

更多详解Java的Spring框架中的注解的用法相关文章请关注PHP中文网!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn