Spring的注解

Spring常见的注解:@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier

 

这几个注解是基于类的,当你需要定义某个类为一个bean时,则在这个类的类名前一行使用类似@Service("XXX")的注解,就相当于把这个类定义为一个bean,bean名称为XXX。当然我们可以定义名称,也可以不定义,不定义名称的话,会默认以类名为bean的名称(类首字母小写)。

 

首先,先看一下这几个注解:@Component、@Repository、@Service、@Controller

 

通过看一些项目代码,我发现@Repository、@Service、@Controller 这几个注解好像是一个类型,其实@Component 跟他们也是一个类型的。

 

Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service和 @Controller ,其实在目前的 Spring 版本中,这三个注解跟@Component 功能是等效的。但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。

 

虽然目前这3 个注释和 @Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用上述注解对分层中的类进行注释。

 

@Service用于标注业务层组件(通常在service层就用这个,一般是service接口的实现类)

 

@Controller用于标注控制层组件(如struts中的action)

 

@Repository用于标注数据访问组件(如DAO组件)

 

@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

例如:

 

@Service 

public class UserServiceImpl implements UserService {    

@Repository 

public class UserDaoImpl implements IUserDao {  

}

 

因为在一个稍大的项目中,往往会涉及到很多组件,如果组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。Spring2.5以后的版本为我们引入了组件自动扫描机制,它会在配置好的类路径下寻找标注了上述注解的类,并把这些类纳入到spring容器中管理。对组件使用注解的作用和在xml文件中使用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.foo.spring”/>    

</beans>

 

component-scan标签默认情况下自动扫描指定路径下的包(含所有子包),将带有@Component、@Repository、@Service、@Controller标签的类自动注册到spring容器。对标记了@Required、@Autowired(spring);@PostConstruct、@PreDestroy、@Resource(JSR250);@WebServiceRef(JAX-WS);@EJB(EJB3); @PersistenceContext、@PersistenceUnit(JPA)等注解的类进行对应的操作使注解生效(这其实就包含了annotation-config标签的作用,所以配置了<context:component-scan base-package=""/>之后,便无需再配置<context:annotation-config/>)。

注意:

在使用注解的情况下,getBean的默认名称是类名(头字母小写),如果想自定义,可以用类似@Service(“aaaaa”)这样的方式来指定。这种bean默认是“singleton”的,如果想改变,可以使用@Scope(“prototype”)的方式来改变bean的作用域。

 

可以使用以下方式指定初始化方法和销毁方法:

 //若想让<bean>实例化之后去执行初始化方法,可以使用@PostConstruct标注在该方法上

@PostConstruct 

public void init() {  

}  

//同样@PreDestroy注解标注在方法上,可以用来指定<bean>销毁时执行的方法

@PreDestroy 

public void destory() {  

}  

 

然后再看后面的几个注解:@Resource、@Autowired、@Qualifier

 

当需要在某个类中定义一个属性,并且该属性是一个已存在的bean,要为该属性赋值我们就用着三个。我们通过看代码可以看到这三个都是定义在一个属性上的,比如:

 

@Resource

private IIocDao iocDao;

@Autowired

private IocService service;

 

那这几个到底有什么区别呢?

我们先看@Resource,它是javax.annotation.Resource; 这个包中,也就是说javaEE中的并不是spring包中的。而且@Resource("xxx") 是可以定义bean名称的,就是说我这个属性要用那个bean来赋值。

 

@Autowired,它是org.springframework.beans.factory.annotation.Autowired 是这个包中,它spring的包。而且它没有@Autowired("xxx"),那我要为这个bean定义名称怎么办?这个时候可以@Qualifier("xxx")定义名称,这个注解也是spring包中的。这个xxx定义bean名称有什么用呢?

如果对于某一个接口,我们定义的该接口的实现类不止有一个,而是两个以上。比如IIocDao这个接口有两个实现类IocDao、IocDao2:

 

package com.ulewo.ioc;

import org.springframework.stereotype.Repository;

 

@Repository

public class IocDao implements IIocDao{

    public void add(){

        System.out.println("调用了dao");

    }

}

 

package com.ulewo.ioc;

import org.springframework.stereotype.Repository;

 

@Repository

public class IocDao2 implements IIocDao{

    public void add(){

        System.out.println("调用了dao2");

    }

}

 

其他不变,我们再运行:testIoc(),控制台打印出 调用了dao,所以在service层中

 

@Resource

private IIocDao iocDao;

 

这个iocDao 注入的是IocDao 这个实现类。奇怪了,它怎么知道我要调用哪个实现呢?

好,我们修改一下,把 service层中的private IIocDao iocDao;改一下,改成 private IIocDao iocDaox 把属性名改一下,再运行,会报错:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: iocDao,iocDao2

 

错误很明显啊,虽然容器中有两个bean iocDao和iocDao2,但是我们定义的属性名的是iocDaox,所以找不到了。所以可以看出来在用 @Repository注解来生成bean的时候,如果没有定义名称那么就会根据类名来生成。所以我们要调用第二个实现的时候可以定义为private IIocDao iocDao2 。我们再运行打印出:调用了dao2,所以可以根据属性名来区分,到底注入那个bean。但是有的人说,我不想定义bean名称跟类实现一样,我要定义其他的名称,那怎么玩呢,方法有2种:

第一种:我们在生成bean的时候就给bean定义个名称

 

@Repository("myIocDao")

public class IocDao implements IIocDao{

    public void add(){

        System.out.println("调用了dao");

    }

}

 

这样就把这个实现类的名称定义为myIocDao了,而不是默认的类名 iocDao。

那么我们在使用这个bean的时候就要这么定义了:

 

@Resource

private IIocDao myIocDao;

 

运行,输出了:调用了dao

 

如果你这里不是用的 myIocDao,你又多加了一个x,成了myIocDaox,你运行会是这样的:

 

 org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: myIocDao,iocDao2

 

所以,想要自定义bean的名称,可以在类注解的时候就指定。

 

第二种:在注入bean的时候指定名称:

 

①先看@Resource

我们在service层先这么定义下:

 

@Resource(name="iocDao")

private IIocDao xxx;

 

注意:

 

@Repository

public class IocDao implements IIocDao{

    public void add(){

        System.out.println("调用了dao");

    }

}

 

这里还是用会默认的,也就是这个实现对应的是 iocDao这bean。如果你要为这个类指定别名bean,@Repository("myIocDao"),那@Resource(name="myIocDao") 就要这么写了。就是这里的name要跟实现类对应的bean名称保持一致。private IIocDao xxx; 这个属性名就随便写了。

 

运行:调用了dao

 

②如果用@Autowired,

那么在service层就要这么定义了

 

@Autowired

@Qualifier("iocDao")

private IIocDao xxx;

 

因为Autowired 不能像Resource 那样带个参数指定一个name,就要用Qualifier来指定了。

 

@Repository

public class IocDao implements IIocDao{

    public void add(){

        System.out.println("调用了dao");

    }

}

 

这里也还是用会默认的,也就是这个实现对应的是 iocDao这bean。如果你要为这个类指定别名bean,@Repository("myIocDao"),那么@Qualifier ("myIocDao") 就要这么写了。就是这里的name要跟实现类对应的bean名称保持一致。private IIocDao xxx; 这个属性名就随便写了。

 

运行:调用了dao

 

而且还可以这么用

 

@Resource

@Qualifier("iocDao")

private IIocDao xxx;

 

等同于

 

@Resource(name="iocDao")

private IIocDao xx;

 

记住一点:@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常。而@Resource默认按 byName自动注入罢了。其实spring注解,最常用的还是根据名称,根据类型和构造方法,用的非常少。所以在多个实现的时候我们定义好bean的名称就行,就不会错乱。所以比较推荐使用@Resource!

 

总结:其实上面主要说了Spring的主要常见的几个注解的使用场景以及使用方法。通过以上的阐述,基本可以得出一个比较保险的套路:@Repository、@Service、@Controller @Resource这四大注解基本就可以满足Spring 的注解使用范围了。

 

补充说明:关于@Autowired的注入方式:

把DAO实现类注入到action的service接口(注意不要是service的实现类)中,注入时不要new 这个注入的类,因为Spring会自动注入,如果手动再new的话会出现错误,然后属性加上@Autowired后不需要getter()和setter()方法,Spring也会自动注入。 

在接口前面标上@Autowired注释使得接口可以被容器注入,如:

@Autowired 

@Qualifier("chinese") 

private Man man; 

当接口存在两个实现类的时候必须使用@Qualifier指定注入哪个实现类,否则可以省略,只写@Autowired。

posted on 2016-08-06 00:10  毛先森  阅读(219)  评论(0编辑  收藏  举报

导航